mirror of
https://github.com/irmen/prog8.git
synced 2026-10-22 05:02:58 +00:00
3049 lines
186 KiB
Kotlin
3049 lines
186 KiB
Kotlin
package prog8.codegen.intermediate
|
|
|
|
import prog8.code.StExtSub
|
|
import prog8.code.StExtSubParameter
|
|
import prog8.code.StNodeType
|
|
import prog8.code.StSub
|
|
import prog8.code.ast.*
|
|
import prog8.code.core.*
|
|
import prog8.intermediate.*
|
|
|
|
|
|
internal class AssignmentGen(private val codeGen: IRCodeGen, private val exprGen: ExpressionGen) {
|
|
|
|
private fun normalizeArrayIndex(result: MutableList<IRCodeChunkBase>, indexTr: ExpressionCodeResult): Pair<Int, DataType> {
|
|
val indexReg = codeGen.canonicalizeIndexReg(result, indexTr)
|
|
val indexDt = if(codeGen.options.compTarget.indexRegType==IRDataType.WORD) DataType.UWORD else DataType.UBYTE
|
|
return indexReg to indexDt
|
|
}
|
|
|
|
internal fun translate(assignment: PtAssignment): IRCodeChunks {
|
|
if(assignment.multiTarget) {
|
|
val values = assignment.value as? PtFunctionCall
|
|
?: throw AssemblyError("only function calls can return multiple values in a multi-assign")
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val funcCall = exprGen.translate(values)
|
|
val assignmentTargets = assignment.children.dropLast(1)
|
|
addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg)
|
|
|
|
val extsub = codeGen.symbolTable.lookup(values.name) as? StExtSub
|
|
if(extsub!=null) {
|
|
require(funcCall.multipleResultRegs.size + funcCall.multipleResultFpRegs.size >= 2)
|
|
if (extsub.returns.size == assignmentTargets.size) {
|
|
// Targets and values match. Assign all the things. Skip 'void' targets.
|
|
// We need to handle both FP registers (FAC1/FAC2) and regular CPU registers
|
|
// Status flag returns MUST be processed first, because their branch-based
|
|
// code needs to read CPU flags immediately after the call, before any
|
|
// LOADHR/STOREM instructions clobber them.
|
|
val fpRegs = funcCall.multipleResultFpRegs.toMutableList()
|
|
val cpuRegs = funcCall.multipleResultRegs.toMutableList()
|
|
|
|
// Pre-consume register numbers in original order to keep indices aligned
|
|
val regNumbers = extsub.returns.map { returns ->
|
|
val isFpRegister = returns.register.registerOrPair in listOf(RegisterOrPair.FAC1, RegisterOrPair.FAC2)
|
|
if(isFpRegister) fpRegs.removeAt(0) else cpuRegs.removeAt(0)
|
|
}
|
|
|
|
val paired = extsub.returns.zip(assignmentTargets).zip(regNumbers)
|
|
val (flagPairs, otherPairs) = paired.partition { (pair, _) ->
|
|
pair.first.register.statusflag != null
|
|
}
|
|
|
|
fun processPair(pair: Pair<Pair<StExtSubParameter, PtNode>, Int>) {
|
|
val (returns, targetStmt) = pair.first
|
|
val regNumber = pair.second
|
|
val target = targetStmt as PtAssignTarget
|
|
if (!target.void) {
|
|
result += assignCpuRegister(returns, regNumber, target)
|
|
}
|
|
}
|
|
|
|
flagPairs.forEach(::processPair)
|
|
otherPairs.forEach(::processPair)
|
|
} else {
|
|
throw AssemblyError("number of values and targets don't match")
|
|
}
|
|
} else {
|
|
val thing = codeGen.symbolTable.lookup(values.name)
|
|
val normalsub = thing as? StSub
|
|
if (normalsub!=null) {
|
|
// note: multi-value returns are passed throug A or AY (for the first value) then cx16.R15 down to R0
|
|
// (this allows unencumbered use of many Rx registers if you don't return that many values)
|
|
val returnregs = (normalsub.astNode!! as IPtSubroutine).returnsWhatWhere(codeGen.options.compTarget)
|
|
assignmentTargets.zip(returnregs).forEach {
|
|
val target = it.first as PtAssignTarget
|
|
if(!target.void) {
|
|
val reg = it.second.first
|
|
val regnum = codeGen.registers.next(codeGen.irType(it.second.second))
|
|
val p = StExtSubParameter("", it.second.second, reg)
|
|
result += assignCpuRegister(p, regnum, target)
|
|
}
|
|
}
|
|
}
|
|
else if(thing?.type==StNodeType.BUILTINFUNC) {
|
|
// note: multi-value returns are passed throug A or AY (for the first value) then cx16.R15 down to R0
|
|
// (this allows unencumbered use of many Rx registers if you don't return that many values)
|
|
val returntypes = BuiltinFunctions.getValue(thing.name).returnTypes
|
|
val signature = PtSubSignature(returntypes.map { DataType.forDt(it) }, values.position)
|
|
val returnregs = signature.returnsWhatWhere(codeGen.options.compTarget)
|
|
assignmentTargets.zip(returnregs).forEach {
|
|
val target = it.first as PtAssignTarget
|
|
if(!target.void) {
|
|
val reg = it.second.first
|
|
val regnum = codeGen.registers.next(codeGen.irType(it.second.second))
|
|
val p = StExtSubParameter("", it.second.second, reg)
|
|
result += assignCpuRegister(p, regnum, target)
|
|
}
|
|
}
|
|
}
|
|
else throw AssemblyError("expected extsub or normal sub or builtin func")
|
|
}
|
|
|
|
return result
|
|
} else {
|
|
if (assignment.target.children.single() is PtIrRegister)
|
|
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
|
|
|
return translateRegularAssign(assignment)
|
|
}
|
|
}
|
|
|
|
private fun assignCpuRegister(returns: StExtSubParameter, regNum: Int, target: PtAssignTarget): IRCodeChunks {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val reg3 = returns.register.registerOrPair
|
|
val (slot3, _) = if (reg3 != null && reg3 !in setOf(RegisterOrPair.FAC1, RegisterOrPair.FAC2))
|
|
exprGen.registerOrStatusflagToSlotAndFlag(RegisterOrStatusflag(reg3, null))
|
|
else null to null
|
|
val m68kSlot3 = slot3?.takeIf { it.value >= 10 }
|
|
if (m68kSlot3 != null) {
|
|
addInstr(result, IRInstructions.hardwareLoad(codeGen.irType(returns.type), regNum, m68kSlot3), null)
|
|
} else when(returns.register.registerOrPair) {
|
|
RegisterOrPair.A -> addInstr(result, IRInstructions.hardwareLoad(IRDataType.BYTE, regNum, CallingConventionSlot(0)), null)
|
|
RegisterOrPair.X -> addInstr(result, IRInstructions.hardwareLoad(IRDataType.BYTE, regNum, CallingConventionSlot(1)), null)
|
|
RegisterOrPair.Y -> addInstr(result, IRInstructions.hardwareLoad(IRDataType.BYTE, regNum, CallingConventionSlot(2)), null)
|
|
RegisterOrPair.AX -> addInstr(result, IRInstructions.hardwareLoad(IRDataType.WORD, regNum, CallingConventionSlot(3)), null)
|
|
RegisterOrPair.AY -> addInstr(result, IRInstructions.hardwareLoad(IRDataType.WORD, regNum, CallingConventionSlot(4)), null)
|
|
RegisterOrPair.XY -> addInstr(result, IRInstructions.hardwareLoad(IRDataType.WORD, regNum, CallingConventionSlot(5)), null)
|
|
in Cx16VirtualRegisters -> addInstr(result, IRInstructions.loadMemory(Opcode.LOADM, codeGen.irType(returns.type), regNum, IRMemory.direct("cx16.${returns.register.registerOrPair.toString().lowercase()}")), null)
|
|
in CombinedLongRegisters -> {
|
|
require(returns.type.isLong)
|
|
val startreg = returns.register.registerOrPair!!.startregname()
|
|
addInstr(result, IRInstructions.loadMemory(Opcode.LOADM, IRDataType.LONG, regNum, IRMemory.direct("cx16.${startreg}")), null)
|
|
}
|
|
RegisterOrPair.FAC1 -> addInstr(result, IRInstructions.unary(Opcode.LOADHFACZERO, IRDataType.FLOAT, regNum), null)
|
|
RegisterOrPair.FAC2 -> addInstr(result, IRInstructions.unary(Opcode.LOADHFACONE, IRDataType.FLOAT, regNum), null)
|
|
null -> if(returns.register.statusflag!=null)
|
|
result += assignCpuStatusFlagReturnvalue(returns.register.statusflag!!, regNum)
|
|
else
|
|
throw AssemblyError("weird CPU register")
|
|
else -> throw AssemblyError("weird CPU register")
|
|
}
|
|
|
|
// build an assignment to store the value in the actual target.
|
|
// Use the return type for the register (matching the LOAD instruction), not the target type.
|
|
// translateRegularAssign will handle byte-to-word extension if needed.
|
|
val assign = PtAssignment(target.position)
|
|
assign.add(target)
|
|
assign.add(PtIrRegister(regNum, returns.type, target.position))
|
|
result += translate(assign)
|
|
return result
|
|
}
|
|
|
|
private fun assignCpuStatusFlagReturnvalue(statusflag: Statusflag, regNum: Int): IRCodeChunks {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
when(statusflag) {
|
|
Statusflag.Pc -> {
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, regNum, 0)
|
|
it += IRInstructions.unary(Opcode.ROXL, IRDataType.BYTE, regNum)
|
|
}
|
|
}
|
|
Statusflag.Pz -> {
|
|
val setLabel = codeGen.createLabelName()
|
|
val endLabel = codeGen.createLabelName()
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.branch(Opcode.BSTEQ, codeLabel(setLabel))
|
|
it += IRInstructions.load(IRDataType.BYTE, regNum, 0)
|
|
it += IRInstructions.jump(codeLabel(endLabel))
|
|
}
|
|
result += IRCodeChunk(setLabel, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, regNum, 1)
|
|
}
|
|
result += IRCodeChunk(endLabel, null)
|
|
}
|
|
Statusflag.Pn -> {
|
|
val setLabel = codeGen.createLabelName()
|
|
val endLabel = codeGen.createLabelName()
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.branch(Opcode.BSTNEG, codeLabel(setLabel))
|
|
it += IRInstructions.load(IRDataType.BYTE, regNum, 0)
|
|
it += IRInstructions.jump(codeLabel(endLabel))
|
|
}
|
|
result += IRCodeChunk(setLabel, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, regNum, 1)
|
|
}
|
|
result += IRCodeChunk(endLabel, null)
|
|
}
|
|
Statusflag.Pv -> {
|
|
val skipLabel = codeGen.createLabelName()
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, regNum, 0)
|
|
it += IRInstructions.branch(Opcode.BSTVC, codeLabel(skipLabel))
|
|
it += IRInstructions.load(IRDataType.BYTE, regNum, 1)
|
|
}
|
|
result += IRCodeChunk(skipLabel, null)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks {
|
|
if(augAssign.target.type.isString)
|
|
throw AssemblyError("cannot assign to str type ${augAssign.position}")
|
|
|
|
// augmented assignment always has just a single target
|
|
if (augAssign.target.children.single() is PtIrRegister)
|
|
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
|
|
|
val target = augAssign.target
|
|
val targetDt = codeGen.irType(target.type)
|
|
val value = augAssign.value
|
|
val memTarget = target.memory
|
|
val constAddress: UInt? = (memTarget?.address as? PtNumber)?.number?.toUInt()
|
|
val symbol = target.identifier?.name
|
|
val array = target.array
|
|
val signed = target.type.isSigned
|
|
val pointerDeref = target.pointerDeref
|
|
val chunks: IRCodeChunks
|
|
|
|
if(pointerDeref!=null) {
|
|
val inplaceInstrs = mutableListOf<IRCodeChunkBase>()
|
|
val (addressReg, fieldOffset) = codeGen.evaluatePointerAddressIntoReg(inplaceInstrs, pointerDeref)
|
|
val oldvalueReg = codeGen.registers.next(targetDt)
|
|
|
|
if((augAssign.operator=="+=" || augAssign.operator=="-=") && (value.asConstInteger()==1 || value.asConstInteger()==2)) {
|
|
// INC/DEC optimization instead of ADD/SUB
|
|
|
|
loadfield(inplaceInstrs, addressReg, fieldOffset, targetDt, oldvalueReg)
|
|
val instr = if(augAssign.operator=="+=") Opcode.INC else Opcode.DEC
|
|
repeat(value.asConstInteger()!!) {
|
|
addInstr(inplaceInstrs, IRInstructions.unary(instr, targetDt, oldvalueReg), null)
|
|
}
|
|
|
|
} else {
|
|
|
|
var operandTr = ExpressionCodeResult(emptyList(), IRDataType.BYTE, -1, -1)
|
|
if(augAssign.operator!="or=" && augAssign.operator!="and=") {
|
|
// for everything except the shortcircuit boolean operators, we can evaluate the value here unconditionally
|
|
operandTr = exprGen.translateExpression(value)
|
|
// note: the instructions to load the value will be placed after the LOADI instruction so that later optimizations about what modification is actually done, are easier
|
|
}
|
|
if(targetDt== IRDataType.FLOAT) {
|
|
|
|
loadfield(inplaceInstrs, addressReg, fieldOffset, targetDt, oldvalueReg)
|
|
inplaceInstrs += operandTr.chunks
|
|
when(augAssign.operator) {
|
|
"+=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.ADDR, targetDt, oldvalueReg, operandTr.resultFpReg), null)
|
|
"-=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.SUBR, targetDt, oldvalueReg, operandTr.resultFpReg), null)
|
|
"*=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.MULR, targetDt, oldvalueReg, operandTr.resultFpReg), null)
|
|
"/=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.DIVSR, targetDt, oldvalueReg, operandTr.resultFpReg), null)
|
|
"%=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.MODR, targetDt, oldvalueReg, operandTr.resultFpReg), null)
|
|
"+" -> { /* inplace + is a no-op */ }
|
|
else -> throw AssemblyError("invalid augmented assign operator for floats ${augAssign.operator}")
|
|
}
|
|
|
|
} else {
|
|
|
|
loadfield(inplaceInstrs, addressReg, fieldOffset, targetDt, oldvalueReg)
|
|
inplaceInstrs += operandTr.chunks
|
|
when(augAssign.operator) {
|
|
"+=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.ADDR, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
"-=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.SUBR, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
"*=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.MULR, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
"/=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.DIVR, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
"%=" -> {
|
|
val opc = if(signed) Opcode.MODSR else Opcode.MODR
|
|
addInstr(inplaceInstrs, IRInstructions.binary(opc, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
}
|
|
"|=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.ORR, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
"&=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.ANDR, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
"^=", "xor=" -> addInstr(inplaceInstrs, IRInstructions.binary(Opcode.XORR, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
"<<=" -> {
|
|
val constCount = value.asConstInteger()
|
|
if(constCount != null) {
|
|
addInstr(inplaceInstrs, IRInstructions.binaryImmediate(Opcode.LSLI, targetDt, oldvalueReg, constCount), null)
|
|
} else {
|
|
addInstr(inplaceInstrs, IRInstructions.binary(Opcode.LSLN, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
}
|
|
}
|
|
">>=" -> {
|
|
val constCount = value.asConstInteger()
|
|
if(constCount != null) {
|
|
val opc = if (signed) Opcode.ASRI else Opcode.LSRI
|
|
addInstr(inplaceInstrs, IRInstructions.binaryImmediate(opc, targetDt, oldvalueReg, constCount), null)
|
|
} else {
|
|
val opc = if (signed) Opcode.ASRN else Opcode.LSRN
|
|
addInstr(inplaceInstrs, IRInstructions.binary(opc, targetDt, oldvalueReg, operandTr.resultReg), null)
|
|
}
|
|
}
|
|
"or=" -> {
|
|
val shortcutLabel = codeGen.createLabelName()
|
|
if(!codeGen.options.compTarget.cpu.statusBitsOnMultiByteOps)
|
|
addInstr(inplaceInstrs, IRInstructions.compareImmediate(targetDt, oldvalueReg, 0), null)
|
|
addInstr(inplaceInstrs, IRInstructions.branch(Opcode.BSTNE, codeLabel(shortcutLabel)), null)
|
|
val valueTr = exprGen.translateExpression(value)
|
|
inplaceInstrs += valueTr.chunks
|
|
addInstr(inplaceInstrs, IRInstructions.binary(Opcode.ORR, targetDt, oldvalueReg, valueTr.resultReg), null)
|
|
inplaceInstrs += IRCodeChunk(shortcutLabel, null)
|
|
}
|
|
"and=" -> {
|
|
val shortcutLabel = codeGen.createLabelName()
|
|
if(!codeGen.options.compTarget.cpu.statusBitsOnMultiByteOps)
|
|
addInstr(inplaceInstrs, IRInstructions.compareImmediate(targetDt, oldvalueReg, 0), null)
|
|
addInstr(inplaceInstrs, IRInstructions.branch(Opcode.BSTEQ, codeLabel(shortcutLabel)), null)
|
|
val valueTr = exprGen.translateExpression(value)
|
|
inplaceInstrs += valueTr.chunks
|
|
addInstr(inplaceInstrs, IRInstructions.binary(Opcode.ANDR, targetDt, oldvalueReg, valueTr.resultReg), null)
|
|
inplaceInstrs += IRCodeChunk(shortcutLabel, null)
|
|
}
|
|
"-" -> addInstr(inplaceInstrs, IRInstructions.unary(Opcode.NEG, targetDt, oldvalueReg), null)
|
|
"~" -> addInstr(inplaceInstrs, IRInstructions.unary(Opcode.INV, targetDt, oldvalueReg), null)
|
|
"not" -> addInstr(inplaceInstrs, IRInstructions.binaryImmediate(Opcode.XOR, targetDt, oldvalueReg, 1), null)
|
|
"+" -> { /* inplace + is a no-op */ }
|
|
else -> throw AssemblyError("invalid augmented assign operator ${augAssign.operator}")
|
|
}
|
|
}
|
|
}
|
|
|
|
codeGen.storeValueAtPointersLocation(inplaceInstrs, addressReg, fieldOffset, pointerDeref.type, false, oldvalueReg)
|
|
chunks = inplaceInstrs
|
|
} else if(array?.pointerderef != null) {
|
|
chunks = fallbackAssign(augAssign)
|
|
} else {
|
|
chunks = when (augAssign.operator) {
|
|
"+=" -> operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
"-=" -> operatorMinusInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
"*=" -> operatorMultiplyInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
"/=" -> operatorDivideInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
"|=" -> operatorOrInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
"or=" -> operatorLogicalOrInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
"&=" -> operatorAndInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
"and=" -> operatorLogicalAndInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
"^=", "xor=" -> operatorXorInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
"<<=" -> operatorShiftLeftInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
">>=" -> operatorShiftRightInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
"%=" -> operatorModuloInplace(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}")
|
|
} ?: fallbackAssign(augAssign)
|
|
}
|
|
|
|
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(augAssign.position)
|
|
return chunks
|
|
}
|
|
|
|
private fun loadfield(
|
|
inplaceInstrs: MutableList<IRCodeChunkBase>,
|
|
addressReg: Int,
|
|
fieldOffset: UByte,
|
|
targetDt: IRDataType,
|
|
oldvalueReg: Int
|
|
) {
|
|
if (targetDt == IRDataType.FLOAT) {
|
|
addInstr(
|
|
inplaceInstrs,
|
|
IRInstructions.loadMemory(Opcode.LOADI, targetDt, oldvalueReg, IRMemory.indirect(addressReg, fieldOffset.toInt())),
|
|
null
|
|
)
|
|
} else {
|
|
addInstr(
|
|
inplaceInstrs,
|
|
IRInstructions.loadMemory(Opcode.LOADI, targetDt, oldvalueReg, IRMemory.indirect(addressReg, fieldOffset.toInt())),
|
|
null
|
|
)
|
|
}
|
|
}
|
|
|
|
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
|
|
val value: PtExpression
|
|
if(origAssign.operator in PrefixOperators) {
|
|
value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position)
|
|
value.add(origAssign.value)
|
|
} else {
|
|
val operator = when(origAssign.operator) {
|
|
in ComparisonOperators -> origAssign.operator
|
|
else -> {
|
|
require(origAssign.operator.endsWith('='))
|
|
origAssign.operator.dropLast(1)
|
|
}
|
|
}
|
|
value = PtBinaryExpression(operator, origAssign.target.type, origAssign.value.position)
|
|
val left: PtExpression = origAssign.target.children.single() as PtExpression
|
|
value.add(left)
|
|
value.add(origAssign.value)
|
|
}
|
|
val normalAssign = PtAssignment(origAssign.position)
|
|
normalAssign.add(origAssign.target)
|
|
normalAssign.add(value)
|
|
return translateRegularAssign(normalAssign)
|
|
}
|
|
|
|
private fun inplacePrefix(operator: String, symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType): IRCodeChunks {
|
|
if(operator=="+")
|
|
return emptyList()
|
|
|
|
if(array!=null)
|
|
return inplacePrefixArray(operator, array)
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
if(constAddress==null && memory!=null) {
|
|
val register = codeGen.registers.next(vmDt)
|
|
val tr = exprGen.translateExpression(memory.address)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
when(operator) {
|
|
"-" -> {
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, register, IRMemory.indirect(tr.resultReg, 0))
|
|
it += IRInstructions.unary(Opcode.NEG, vmDt, register)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, register, IRMemory.indirect(tr.resultReg, 0))
|
|
}
|
|
}
|
|
"~" -> {
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, register, IRMemory.indirect(tr.resultReg, 0))
|
|
it += IRInstructions.unary(Opcode.INV, vmDt, register)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, register, IRMemory.indirect(tr.resultReg, 0))
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
val directMem = if(constAddress!=null) IRMemory.direct(constAddress) else IRMemory.direct(symbol!!)
|
|
when (operator) {
|
|
"-" -> addInstr(result, IRInstructions.memoryOp(Opcode.NEGM, vmDt, directMem), null)
|
|
"~" -> addInstr(result, IRInstructions.memoryOp(Opcode.INVM, vmDt, directMem), null)
|
|
"not" -> {
|
|
val regMask = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, regMask, 1)
|
|
it += IRInstructions.memoryOp(Opcode.XORM, vmDt, directMem, regMask)
|
|
}
|
|
}
|
|
else -> throw AssemblyError("weird prefix operator")
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun inplacePrefixArray(operator: String, array: PtArrayIndexer): IRCodeChunks {
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val vmDt = codeGen.irType(array.type)
|
|
val constIndex = array.index.asConstInteger()
|
|
|
|
fun loadIndex(): Int {
|
|
val tr = exprGen.translateExpression(array.index)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
val (indexReg, _) = normalizeArrayIndex(result, tr)
|
|
return indexReg
|
|
}
|
|
|
|
if(array.splitWords) {
|
|
// handle split LSB/MSB arrays
|
|
when(operator) {
|
|
"+" -> { }
|
|
"-" -> {
|
|
val arrayVariableName = array.variable!!.name
|
|
val skipCarryLabel = codeGen.createLabelName()
|
|
if(constIndex!=null) {
|
|
val negLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.NEGM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex)), null)
|
|
addInstr(result, IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, negLsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex)), null)
|
|
if(!codeGen.options.compTarget.cpu.statusBitsOnMultiByteOps)
|
|
addInstr(result, IRInstructions.compareImmediate(IRDataType.BYTE, negLsbReg, 0), null)
|
|
addInstr(result, IRInstructions.branch(Opcode.BSTEQ, codeLabel(skipCarryLabel)), null)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.INCM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex)), null)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.NEGM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex)), skipCarryLabel)
|
|
} else {
|
|
val indexReg = loadIndex()
|
|
val registerLsb = codeGen.registers.next(IRDataType.BYTE)
|
|
val registerMsb = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, registerLsb, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.unary(Opcode.NEG, IRDataType.BYTE, registerLsb)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, registerLsb, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, registerMsb, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.unary(Opcode.NEG, IRDataType.BYTE, registerMsb)
|
|
it += IRInstructions.compareImmediate(IRDataType.BYTE, registerLsb, 0)
|
|
it += IRInstructions.branch(Opcode.BSTEQ, codeLabel(skipCarryLabel))
|
|
it += IRInstructions.unary(Opcode.DEC, IRDataType.BYTE, registerMsb)
|
|
}
|
|
result += IRCodeChunk(skipCarryLabel, null).also {
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, registerMsb, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
}
|
|
"~" -> {
|
|
val arrayVariableName = array.variable!!.name
|
|
if(constIndex!=null) {
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.INVM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex)), null)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.INVM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex)), null)
|
|
} else {
|
|
val indexReg = loadIndex()
|
|
val register = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, register, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.unary(Opcode.INV, IRDataType.BYTE, register)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, register, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, register, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.unary(Opcode.INV, IRDataType.BYTE, register)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, register, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
}
|
|
else -> throw AssemblyError("weird prefix operator")
|
|
}
|
|
return result
|
|
}
|
|
|
|
// normal array.
|
|
|
|
when(operator) {
|
|
"+" -> { }
|
|
"-" -> {
|
|
val arrayVariableName = array.variable!!.name
|
|
if(constIndex!=null) {
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.NEGM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize)), null)
|
|
} else {
|
|
val indexReg = loadIndex()
|
|
val register = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, register, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType, scale=eltSize))
|
|
it += IRInstructions.unary(Opcode.NEG, vmDt, register)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, register, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType, scale=eltSize))
|
|
}
|
|
}
|
|
}
|
|
"~" -> {
|
|
val arrayVariableName = array.variable!!.name
|
|
if(constIndex!=null) {
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.INVM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize)), null)
|
|
} else {
|
|
val indexReg = loadIndex()
|
|
val register = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, register, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType, scale=eltSize))
|
|
it += IRInstructions.unary(Opcode.INV, vmDt, register)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, register, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType, scale=eltSize))
|
|
}
|
|
}
|
|
}
|
|
"not" -> {
|
|
val arrayVariableName = array.variable!!.name
|
|
val register = codeGen.registers.next(vmDt)
|
|
if(constIndex!=null) {
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, register, 1)
|
|
it += IRInstructions.memoryOp(Opcode.XORM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), register)
|
|
}
|
|
} else {
|
|
val indexReg = loadIndex()
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, register, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binaryImmediate(Opcode.XOR, vmDt, register, 1)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, register, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
}
|
|
else -> throw AssemblyError("weird prefix operator")
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunks {
|
|
if(assignment.target.type.isString) {
|
|
// assigning array and string values is done via an explicit memcopy/stringcopy function calls.
|
|
throw AssemblyError("cannot assign to str type ${assignment.position}")
|
|
}
|
|
|
|
val valueDt = codeGen.irType(assignment.value.type)
|
|
val targetDt = codeGen.irType(assignment.target.type)
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
|
|
var valueRegister = -1
|
|
var valueFpRegister = -1
|
|
val zero = codeGen.isZero(assignment.value)
|
|
// STOREIM only helps when the target is a simple identifier or a fixed address;
|
|
// for computed memory targets we still need a register to hold the value.
|
|
val canUseStoreIm = assignment.target.identifier != null ||
|
|
(assignment.target.memory?.address is PtNumber)
|
|
val constInt = if(canUseStoreIm && targetDt != IRDataType.FLOAT && !zero) assignment.value.asConstInteger() else null
|
|
val constFloat = if(canUseStoreIm && targetDt == IRDataType.FLOAT && !zero) assignment.value.asConstValue() else null
|
|
if(!zero && constInt==null && constFloat==null) {
|
|
// calculate the assignment value
|
|
if (valueDt == IRDataType.FLOAT) {
|
|
val tr = exprGen.translateExpression(assignment.value)
|
|
valueFpRegister = tr.resultFpReg
|
|
addToResult(result, tr, -1, valueFpRegister)
|
|
} else {
|
|
// determine if value needs extension or truncation to match target type
|
|
// extension happens for byte→word, byte→long/pointer, or word→long/pointer
|
|
// dst implied by opcode: EXT B/W = b->w / w->l, EXTL B = b->l (single type specifier, see IRInstructions.kt:834)
|
|
val isPointerLong = codeGen.options.compTarget.POINTER_MEM_SIZE > 2u
|
|
val extendSourceDt: IRDataType?
|
|
val extendDestDt: IRDataType?
|
|
val extendSigned: Boolean
|
|
run {
|
|
val valueIsSigned = assignment.value.type.isSigned
|
|
when {
|
|
targetDt == valueDt -> { extendSourceDt = null; extendDestDt = null; extendSigned = false }
|
|
targetDt==IRDataType.WORD && valueDt==IRDataType.BYTE -> { extendSourceDt = IRDataType.BYTE; extendDestDt = IRDataType.WORD; extendSigned = valueIsSigned }
|
|
targetDt==IRDataType.POINTER && valueDt==IRDataType.BYTE -> {
|
|
if(isPointerLong) { extendSourceDt = IRDataType.BYTE; extendDestDt = IRDataType.LONG; extendSigned = valueIsSigned }
|
|
else { extendSourceDt = IRDataType.BYTE; extendDestDt = IRDataType.WORD; extendSigned = valueIsSigned }
|
|
}
|
|
targetDt==IRDataType.LONG && valueDt==IRDataType.BYTE -> { extendSourceDt = IRDataType.BYTE; extendDestDt = IRDataType.LONG; extendSigned = valueIsSigned }
|
|
targetDt==IRDataType.LONG && valueDt==IRDataType.WORD -> { extendSourceDt = IRDataType.WORD; extendDestDt = IRDataType.LONG; extendSigned = valueIsSigned }
|
|
targetDt==IRDataType.POINTER && valueDt==IRDataType.WORD -> {
|
|
if(isPointerLong) { extendSourceDt = IRDataType.WORD; extendDestDt = IRDataType.LONG; extendSigned = valueIsSigned }
|
|
else { extendSourceDt = null; extendDestDt = null; extendSigned = false }
|
|
}
|
|
targetDt==IRDataType.POINTER && valueDt==IRDataType.LONG -> { extendSourceDt = null; extendDestDt = null; extendSigned = false }
|
|
valueDt==IRDataType.POINTER && targetDt==IRDataType.WORD -> { extendSourceDt = null; extendDestDt = null; extendSigned = false } // truncation via LSIG elsewhere, or no op if same size
|
|
valueDt==IRDataType.POINTER && targetDt==IRDataType.LONG -> {
|
|
if(isPointerLong) { extendSourceDt = null; extendDestDt = null; extendSigned = false }
|
|
else { extendSourceDt = IRDataType.WORD; extendDestDt = IRDataType.LONG; extendSigned = valueIsSigned }
|
|
}
|
|
valueDt==IRDataType.LONG && targetDt==IRDataType.WORD -> { extendSourceDt = null; extendDestDt = null; extendSigned = false }
|
|
valueDt==IRDataType.LONG && targetDt==IRDataType.POINTER -> {
|
|
if(isPointerLong) { extendSourceDt = null; extendDestDt = null; extendSigned = false }
|
|
else { extendSourceDt = null; extendDestDt = null; extendSigned = false }
|
|
}
|
|
else -> throw AssemblyError("assignment value and target dt mismatch: $valueDt -> $targetDt")
|
|
}
|
|
}
|
|
fun extOpcode(src: IRDataType, dest: IRDataType, signed: Boolean): Opcode = when {
|
|
src==IRDataType.BYTE && dest==IRDataType.WORD -> if(signed) Opcode.EXTS else Opcode.EXT
|
|
src==IRDataType.WORD && dest==IRDataType.LONG -> if(signed) Opcode.EXTS else Opcode.EXT
|
|
src==IRDataType.BYTE && dest==IRDataType.LONG -> if(signed) Opcode.EXTLS else Opcode.EXTL
|
|
else -> throw AssemblyError("unsupported extension $src -> $dest")
|
|
}
|
|
if (assignment.value is PtIrRegister) {
|
|
valueRegister = (assignment.value as PtIrRegister).register
|
|
if(extendSourceDt != null) {
|
|
val opcode = extOpcode(extendSourceDt, extendDestDt!!, extendSigned)
|
|
valueRegister = codeGen.registers.next(extendDestDt)
|
|
addInstr(result, IRInstructions.binary(opcode, extendSourceDt, valueRegister, (assignment.value as PtIrRegister).register), null)
|
|
}
|
|
} else {
|
|
val tr = exprGen.translateExpression(assignment.value)
|
|
valueRegister = tr.resultReg
|
|
addToResult(result, tr, valueRegister, -1)
|
|
if(extendSourceDt != null) {
|
|
val opcode = extOpcode(extendSourceDt, extendDestDt!!, extendSigned)
|
|
valueRegister = codeGen.registers.next(extendDestDt)
|
|
addInstr(result, IRInstructions.binary(opcode, extendSourceDt, valueRegister, tr.resultReg), null)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
with(assignment.target) {
|
|
when {
|
|
identifier != null -> {
|
|
val instruction = when {
|
|
zero -> IRInstructions.storeZero(Opcode.STOREZM, targetDt, IRMemory.direct(identifier!!.name))
|
|
constInt != null -> {
|
|
val v = when(targetDt) {
|
|
IRDataType.BYTE -> constInt and 0xff
|
|
IRDataType.WORD, IRDataType.POINTER -> constInt and 0xffff
|
|
IRDataType.LONG -> constInt
|
|
else -> throw AssemblyError("invalid target dt $targetDt for const store")
|
|
}
|
|
IRInstructions.storeImmediate(targetDt, v, IRMemory.direct(identifier!!.name))
|
|
}
|
|
constFloat != null -> {
|
|
IRInstructions.storeImmediateFloat(constFloat, IRMemory.direct(identifier!!.name))
|
|
}
|
|
targetDt == IRDataType.FLOAT -> {
|
|
require(valueFpRegister>=0)
|
|
IRInstructions.storeMemory(Opcode.STOREM, targetDt, valueFpRegister, IRMemory.direct(identifier!!.name))
|
|
}
|
|
else -> {
|
|
require(valueRegister>=0)
|
|
IRInstructions.storeMemory(Opcode.STOREM, targetDt, valueRegister, IRMemory.direct(identifier!!.name))
|
|
}
|
|
}
|
|
result += IRCodeChunk(null, null).also { it += instruction }
|
|
return result
|
|
}
|
|
memory != null -> {
|
|
if(tryFoldStructArrayDirectWrite(memory!!.address, zero, valueRegister, targetDt, result)) return result
|
|
require(targetDt == IRDataType.BYTE) { "must be byte type ${memory!!.position}"}
|
|
if(zero) {
|
|
if(memory!!.address is PtNumber) {
|
|
val chunk = IRCodeChunk(null, null).also { it += IRInstructions.storeZero(Opcode.STOREZM, targetDt, IRMemory.direct((memory!!.address as PtNumber).number.toUInt().toAddress())) }
|
|
result += chunk
|
|
} else {
|
|
val (address, offset) = exprGen.getAddressAndOffset(memory!!.address)
|
|
if(address!=null) {
|
|
val tr = exprGen.translateExpression(address)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, IRInstructions.storeZero(Opcode.STOREZI, targetDt, IRMemory.indirect(tr.resultReg, offset!!)), null)
|
|
} else {
|
|
val tr = exprGen.translateExpression(memory!!.address)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, IRInstructions.storeZero(Opcode.STOREZI, targetDt, IRMemory.indirect(tr.resultReg, 0)), null)
|
|
}
|
|
}
|
|
} else {
|
|
val constAddress = memory!!.address as? PtNumber
|
|
if(constAddress!=null) {
|
|
val storeIns = when {
|
|
constInt != null -> {
|
|
val v = when(targetDt) {
|
|
IRDataType.BYTE -> constInt and 0xff
|
|
IRDataType.WORD, IRDataType.POINTER -> constInt and 0xffff
|
|
IRDataType.LONG -> constInt
|
|
}
|
|
IRInstructions.storeImmediate(targetDt, v, IRMemory.direct(constAddress.number.toUInt().toAddress()))
|
|
}
|
|
else -> null
|
|
} ?: IRInstructions.storeMemory(Opcode.STOREM, targetDt, valueRegister, IRMemory.direct(constAddress.number.toUInt().toAddress()))
|
|
addInstr(result, storeIns, null)
|
|
return result
|
|
}
|
|
val ptrWithOffset = memory!!.address as? PtBinaryExpression
|
|
if(ptrWithOffset!=null) {
|
|
if(ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier) {
|
|
val constOffset = (ptrWithOffset.right as? PtNumber)?.number?.toInt()
|
|
if(constOffset in 0..65535) {
|
|
val ptrIdentifier = ptrWithOffset.left as PtIdentifier
|
|
val dt = if(codeGen.options.compTarget.POINTER_MEM_SIZE > 2u && ptrIdentifier.type.isLong)
|
|
IRDataType.POINTER else IRDataType.WORD
|
|
val pointerReg = codeGen.registers.next(dt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, dt, pointerReg, IRMemory.direct(ptrIdentifier.name))
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, valueRegister, IRMemory.indirect(pointerReg, constOffset!!))
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
}
|
|
|
|
val tr = exprGen.translateExpression(memory!!.address)
|
|
val addressReg = tr.resultReg
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, IRInstructions.storeMemory(Opcode.STOREI, targetDt, valueRegister, IRMemory.indirect(addressReg, 0)), null)
|
|
return result
|
|
}
|
|
|
|
return result
|
|
}
|
|
array != null -> {
|
|
val eltSize = codeGen.program.memsizer.memorySize(array!!.type, null)
|
|
val variable = array!!.variable
|
|
if(variable==null)
|
|
translateRegularAssignPointerIndexed(result, array!!.pointerderef!!, eltSize, array!!, zero, targetDt, valueRegister, valueFpRegister)
|
|
else if(variable.type.isPointer)
|
|
assignToIndexedSimplePointer(result, variable, eltSize, array!!, zero, targetDt, valueRegister, valueFpRegister)
|
|
else
|
|
translateRegularAssignArrayIndexed(result, variable.name, eltSize, array!!, zero, targetDt, valueRegister, valueFpRegister)
|
|
return result
|
|
}
|
|
pointerDeref != null -> {
|
|
val (addressReg, offset) = codeGen.evaluatePointerAddressIntoReg(result, pointerDeref!!)
|
|
val actualValueReg = if(pointerDeref!!.type.isFloat) valueFpRegister else valueRegister
|
|
codeGen.storeValueAtPointersLocation(result, addressReg, offset, pointerDeref!!.type, zero, actualValueReg)
|
|
return result
|
|
|
|
}
|
|
else -> {
|
|
throw AssemblyError("weird assigntarget")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun assignToIndexedSimplePointer(
|
|
result: MutableList<IRCodeChunkBase>,
|
|
targetIdent: PtIdentifier,
|
|
eltSize: Int,
|
|
targetArray: PtArrayIndexer,
|
|
zeroValue: Boolean,
|
|
targetDt: IRDataType,
|
|
valueRegister: Int,
|
|
valueFpRegister: Int
|
|
) {
|
|
val pointerTr = exprGen.translateExpression(targetIdent)
|
|
result += pointerTr.chunks
|
|
val pointerReg = pointerTr.resultReg
|
|
|
|
val constIndex = targetArray.index.asConstInteger()
|
|
if(zeroValue) {
|
|
if(constIndex!=null) {
|
|
val offset = eltSize * constIndex
|
|
addInstr(result, IRInstructions.binaryImmediate(Opcode.ADD, IRDataType.POINTER, pointerReg, offset), null)
|
|
} else {
|
|
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, true, targetArray.splitWords)
|
|
result += code
|
|
if(eltSize!=1)
|
|
result += codeGen.multiplyByConst(DataType.UWORD, indexReg, eltSize)
|
|
addInstr(result, IRInstructions.binary(Opcode.ADDR, IRDataType.POINTER, pointerReg, indexReg), null)
|
|
}
|
|
codeGen.storeValueAtPointersLocation(result, pointerReg, 0u, targetIdent.type.dereference(), true, -1)
|
|
} else {
|
|
if(constIndex!=null) {
|
|
val offset = eltSize * constIndex
|
|
addInstr(result, IRInstructions.binaryImmediate(Opcode.ADD, IRDataType.POINTER, pointerReg, offset), null)
|
|
} else {
|
|
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, true, targetArray.splitWords)
|
|
result += code
|
|
if(eltSize!=1)
|
|
result += codeGen.multiplyByConst(DataType.UWORD, indexReg, eltSize)
|
|
addInstr(result, IRInstructions.binary(Opcode.ADDR, IRDataType.POINTER, pointerReg, indexReg), null)
|
|
}
|
|
val realValueReg = if(targetDt == IRDataType.FLOAT) valueFpRegister else valueRegister
|
|
codeGen.storeValueAtPointersLocation(result, pointerReg, 0u, targetIdent.type.dereference(), false, realValueReg)
|
|
}
|
|
}
|
|
|
|
private fun translateRegularAssignArrayIndexed(
|
|
result: MutableList<IRCodeChunkBase>,
|
|
variable: String,
|
|
eltSize: Int,
|
|
targetArray: PtArrayIndexer,
|
|
zero: Boolean,
|
|
targetDt: IRDataType,
|
|
valueRegister: Int,
|
|
valueFpRegister: Int
|
|
) {
|
|
val fixedIndex = targetArray.index.asConstInteger()
|
|
if(zero) {
|
|
if(fixedIndex!=null) {
|
|
val chunk = IRCodeChunk(null, null).also {
|
|
if(targetArray.splitWords) {
|
|
it += IRInstructions.storeZero(Opcode.STOREZM, IRDataType.BYTE, IRMemory.direct("${variable}_lsb", fixedIndex))
|
|
it += IRInstructions.storeZero(Opcode.STOREZM, IRDataType.BYTE, IRMemory.direct("${variable}_msb", fixedIndex))
|
|
}
|
|
else
|
|
it += IRInstructions.storeZero(Opcode.STOREZM, targetDt, IRMemory.direct(variable, fixedIndex*eltSize))
|
|
}
|
|
result += chunk
|
|
} else {
|
|
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, codeGen.wordArrayIndex, targetArray.splitWords)
|
|
result += code
|
|
val scaleZX = if(targetArray.splitWords) 1 else eltSize
|
|
result += IRCodeChunk(null, null).also {
|
|
if(targetArray.splitWords) {
|
|
it += IRInstructions.storeZero(Opcode.STOREZX, IRDataType.BYTE, IRMemory.indexed(variable+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.storeZero(Opcode.STOREZX, IRDataType.BYTE, IRMemory.indexed(variable+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
else
|
|
it += IRInstructions.storeZero(Opcode.STOREZX, targetDt, IRMemory.indexed(variable, indexReg, codeGen.options.compTarget.indexRegType, scale=scaleZX))
|
|
}
|
|
}
|
|
} else {
|
|
if(targetDt== IRDataType.FLOAT) {
|
|
if(fixedIndex!=null) {
|
|
val offset = fixedIndex*eltSize
|
|
val chunk = IRCodeChunk(null, null).also {
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, targetDt, valueFpRegister, IRMemory.direct(variable, offset))
|
|
}
|
|
result += chunk
|
|
} else {
|
|
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, codeGen.wordArrayIndex, targetArray.splitWords)
|
|
result += code
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, targetDt, valueFpRegister, IRMemory.indexed(variable, indexReg, codeGen.options.compTarget.indexRegType, scale=eltSize))
|
|
}
|
|
}
|
|
} else {
|
|
if(fixedIndex!=null) {
|
|
val chunk = IRCodeChunk(null, null).also {
|
|
if(targetArray.splitWords) {
|
|
val lsbmsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, lsbmsbReg, valueRegister)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, lsbmsbReg, IRMemory.direct("${variable}_lsb", fixedIndex))
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, lsbmsbReg, valueRegister)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, lsbmsbReg, IRMemory.direct("${variable}_msb", fixedIndex))
|
|
}
|
|
else
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, targetDt, valueRegister, IRMemory.direct(variable, fixedIndex*eltSize))
|
|
}
|
|
result += chunk
|
|
} else {
|
|
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, codeGen.wordArrayIndex, targetArray.splitWords)
|
|
result += code
|
|
result += IRCodeChunk(null, null).also {
|
|
if(targetArray.splitWords) {
|
|
val lsbmsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, lsbmsbReg, valueRegister)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, lsbmsbReg, IRMemory.indexed("${variable}_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, lsbmsbReg, valueRegister)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, lsbmsbReg, IRMemory.indexed("${variable}_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
else
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, targetDt, valueRegister, IRMemory.indexed(variable, indexReg, codeGen.options.compTarget.indexRegType, scale=eltSize))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun translateRegularAssignPointerIndexed(
|
|
result: MutableList<IRCodeChunkBase>,
|
|
pointerderef: PtPointerDeref,
|
|
eltSize: Int,
|
|
targetArray: PtArrayIndexer,
|
|
zero: Boolean,
|
|
targetDt: IRDataType,
|
|
valueRegister: Int,
|
|
valueFpRegister: Int
|
|
) {
|
|
val pointerTr = exprGen.translateExpression(pointerderef)
|
|
result += pointerTr.chunks
|
|
val pointerReg = pointerTr.resultReg
|
|
|
|
val fixedIndex = targetArray.index.asConstInteger()
|
|
if(fixedIndex!=null) {
|
|
val offset = fixedIndex*eltSize
|
|
if(zero) {
|
|
addInstr(result, IRInstructions.storeZero(Opcode.STOREZI, targetDt, IRMemory.indirect(pointerReg, offset)), null)
|
|
} else {
|
|
addInstr(
|
|
result,
|
|
if (targetDt == IRDataType.FLOAT)
|
|
IRInstructions.storeMemory(Opcode.STOREI, IRDataType.FLOAT, valueFpRegister, IRMemory.indirect(pointerReg, offset))
|
|
else
|
|
IRInstructions.storeMemory(Opcode.STOREI, targetDt, valueRegister, IRMemory.indirect(pointerReg, offset)), null
|
|
)
|
|
}
|
|
} else {
|
|
// index is an expression
|
|
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, true, targetArray.splitWords)
|
|
result += code
|
|
if(eltSize!=1)
|
|
result += codeGen.multiplyByConst(DataType.UWORD, indexReg, eltSize)
|
|
addInstr(result, IRInstructions.binary(Opcode.ADDR, IRDataType.POINTER, pointerReg, indexReg), null)
|
|
if(zero) {
|
|
addInstr(result, IRInstructions.storeZero(Opcode.STOREZI, targetDt, IRMemory.indirect(pointerReg, 0)), null)
|
|
} else {
|
|
addInstr(result, if(targetDt== IRDataType.FLOAT)
|
|
IRInstructions.storeMemory(Opcode.STOREI, IRDataType.FLOAT, valueFpRegister, IRMemory.indirect(pointerReg, 0))
|
|
else
|
|
IRInstructions.storeMemory(Opcode.STOREI, targetDt, valueRegister, IRMemory.indirect(pointerReg, 0))
|
|
, null)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun operatorAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
|
|
if(array!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
if(constIndex!=null && constValue!=null) {
|
|
if(array.splitWords) {
|
|
val valueRegLsb = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueRegMsb = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, valueRegLsb, constValue and 255)
|
|
it += IRInstructions.load(IRDataType.BYTE, valueRegMsb, constValue shr 8)
|
|
it += IRInstructions.memoryOp(Opcode.ANDM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex), valueRegLsb)
|
|
it += IRInstructions.memoryOp(Opcode.ANDM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex), valueRegMsb)
|
|
}
|
|
} else {
|
|
val valueReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, valueReg, constValue)
|
|
it += IRInstructions.memoryOp(Opcode.ANDM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
// Non-const cases - handle split and non-split arrays differently
|
|
if(array.splitWords) {
|
|
// Split word array: extract operand bytes and AND separately
|
|
if(constIndex!=null) {
|
|
// Constant index, non-constant value
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
if(valueTr.resultReg < 0) return null
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, lsbReg, valueTr.resultReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, msbReg, valueTr.resultReg)
|
|
it += IRInstructions.memoryOp(Opcode.ANDM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex), lsbReg)
|
|
it += IRInstructions.memoryOp(Opcode.ANDM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex), msbReg)
|
|
}
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX for each byte array
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, _) = normalizeArrayIndex(result, indexTr)
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
if(valueTr.resultReg < 0) return null
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, valLsbReg, valueTr.resultReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, valMsbReg, valueTr.resultReg)
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, lsbReg, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, msbReg, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.ANDR, IRDataType.BYTE, lsbReg, valLsbReg)
|
|
it += IRInstructions.binary(Opcode.ANDR, IRDataType.BYTE, msbReg, valMsbReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, lsbReg, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, msbReg, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
return result
|
|
}
|
|
// Non-split array cases
|
|
if(constIndex!=null) {
|
|
// Constant index, non-constant value
|
|
val arrayVariableName = array.variable!!.name
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.ANDM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX/ANDR/STOREX
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(result, indexTr)
|
|
val arrayVarName = array.variable!!.name
|
|
// Multiply index by element size for LOADX/STOREX
|
|
if(eltSize > 1) {
|
|
result += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
}
|
|
if(constValue!=null) {
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
val constReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVarName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.load(vmDt, constReg, constValue)
|
|
it += IRInstructions.binary(Opcode.ANDR, vmDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVarName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVarName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.ANDR, vmDt, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVarName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
// Memory target with non-constant address
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(result, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.binary(Opcode.ANDR, IRDataType.BYTE, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.ANDR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.ANDM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.ANDM, vmDt, IRMemory.direct(symbol!!), tr.resultReg),null)
|
|
return result
|
|
}
|
|
|
|
private fun operatorLogicalAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
|
|
if(array!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
if(constIndex!=null && constValue!=null) {
|
|
if(array.splitWords) {
|
|
throw AssemblyError("logical and on (split) word array should not happen")
|
|
} else {
|
|
val valueReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, valueReg, constValue)
|
|
it += IRInstructions.memoryOp(Opcode.ANDM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
// Non-const cases for non-split arrays (logical and = bitwise and for arrays)
|
|
if(constIndex!=null) {
|
|
// Constant index, non-constant value
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.ANDM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, _) = normalizeArrayIndex(result, indexTr)
|
|
if(constValue!=null) {
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
val constReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.load(vmDt, constReg, constValue)
|
|
it += IRInstructions.binary(Opcode.ANDR, vmDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.ANDR, vmDt, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
// Memory target with non-constant address
|
|
val memResult = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(memResult, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(memResult, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.simple(Opcode.ANDR)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.ANDR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
return memResult
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val tr = exprGen.translateExpression(operand)
|
|
if(!operand.isSimple()) {
|
|
// short-circuit LEFT and RIGHT --> if LEFT then RIGHT else LEFT (== if !LEFT then LEFT else RIGHT)
|
|
val inplaceReg = codeGen.registers.next(vmDt)
|
|
val shortcutLabel = codeGen.createLabelName()
|
|
result += IRCodeChunk(null, null).also {
|
|
it += if(constAddress!=null)
|
|
IRInstructions.loadMemory(Opcode.LOADM, vmDt, inplaceReg, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.loadMemory(Opcode.LOADM, vmDt, inplaceReg, IRMemory.direct(symbol!!))
|
|
if(!codeGen.options.compTarget.cpu.statusBitsOnMultiByteOps)
|
|
it += IRInstructions.compareImmediate(vmDt, inplaceReg, 0)
|
|
it += IRInstructions.branch(Opcode.BSTEQ, codeLabel(shortcutLabel))
|
|
}
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.storeMemory(Opcode.STOREM, vmDt, tr.resultReg, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.storeMemory(Opcode.STOREM, vmDt, tr.resultReg, IRMemory.direct(symbol!!)), null)
|
|
result += IRCodeChunk(shortcutLabel, null)
|
|
} else {
|
|
// normal evaluation, it is *likely* shorter and faster because of the simple operands.
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.ANDM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.ANDM, vmDt, IRMemory.direct(symbol!!), tr.resultReg),null)
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
|
|
if(array!=null) {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
if(constIndex!=null && constValue!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
if(array.splitWords) {
|
|
val valueRegLsb = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueRegMsb = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, valueRegLsb, constValue and 255)
|
|
it += IRInstructions.load(IRDataType.BYTE, valueRegMsb, constValue shr 8)
|
|
it += IRInstructions.memoryOp(Opcode.ORM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex), valueRegLsb)
|
|
it += IRInstructions.memoryOp(Opcode.ORM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex), valueRegMsb)
|
|
}
|
|
} else {
|
|
val valueReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, valueReg, constValue)
|
|
it += IRInstructions.memoryOp(Opcode.ORM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
// Non-const cases - handle split and non-split arrays differently
|
|
if(array.splitWords) {
|
|
val arrayVariableName = array.variable!!.name
|
|
if(constIndex!=null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
if(valueTr.resultReg < 0) return null
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, lsbReg, valueTr.resultReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, msbReg, valueTr.resultReg)
|
|
it += IRInstructions.memoryOp(Opcode.ORM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex), lsbReg)
|
|
it += IRInstructions.memoryOp(Opcode.ORM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex), msbReg)
|
|
}
|
|
return result
|
|
}
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, _) = normalizeArrayIndex(result, indexTr)
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
if(valueTr.resultReg < 0) return null
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, valLsbReg, valueTr.resultReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, valMsbReg, valueTr.resultReg)
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, lsbReg, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, msbReg, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.ORR, IRDataType.BYTE, lsbReg, valLsbReg)
|
|
it += IRInstructions.binary(Opcode.ORR, IRDataType.BYTE, msbReg, valMsbReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, lsbReg, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, msbReg, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
return result
|
|
}
|
|
// Non-split array cases
|
|
if(constIndex!=null) {
|
|
val arrayVarName = array.variable!!.name
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.ORM, vmDt, IRMemory.direct(arrayVarName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX/ORR/STOREX
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(result, indexTr)
|
|
val arrayVarName2 = array.variable!!.name
|
|
// Multiply index by element size for LOADX/STOREX
|
|
if(eltSize > 1) {
|
|
result += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
}
|
|
if(constValue!=null) {
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
val constReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.load(vmDt, constReg, constValue)
|
|
it += IRInstructions.binary(Opcode.ORR, vmDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.ORR, vmDt, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
// Memory target with non-constant address
|
|
val memResult = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(memResult, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(memResult, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.binary(Opcode.ORR, IRDataType.BYTE, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.ORR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
return memResult
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.ORM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.ORM, vmDt, IRMemory.direct(symbol!!), tr.resultReg), null)
|
|
return result
|
|
}
|
|
|
|
private fun operatorLogicalOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
|
|
if(array!=null) {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
if(constIndex!=null && constValue!=null) {
|
|
if(array.splitWords) {
|
|
throw AssemblyError("logical or on (split) word array should not happen")
|
|
} else {
|
|
val arrayVariableName = array.variable!!.name
|
|
val valueReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, valueReg, constValue)
|
|
it += IRInstructions.memoryOp(Opcode.ORM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
// Non-const cases - split words not supported for logical or
|
|
if(array.splitWords) {
|
|
throw AssemblyError("logical or on (split) word array with non-const operand should not happen")
|
|
}
|
|
// Non-split array cases
|
|
if(constIndex!=null) {
|
|
val arrayVarName = array.variable!!.name
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.ORM, vmDt, IRMemory.direct(arrayVarName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, _) = normalizeArrayIndex(result, indexTr)
|
|
val arrayVarName2 = array.variable!!.name
|
|
if(constValue!=null) {
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
val constReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.load(vmDt, constReg, constValue)
|
|
it += IRInstructions.binary(Opcode.ORR, vmDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.ORR, vmDt, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
// Memory target with non-constant address
|
|
val memResult = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(memResult, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(memResult, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.binary(Opcode.ORR, IRDataType.BYTE, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.ORR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
return memResult
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val tr = exprGen.translateExpression(operand)
|
|
if(!operand.isSimple()) {
|
|
// short-circuit LEFT or RIGHT --> if LEFT then LEFT else RIGHT
|
|
val inplaceReg = codeGen.registers.next(vmDt)
|
|
val shortcutLabel = codeGen.createLabelName()
|
|
result += IRCodeChunk(null, null).also {
|
|
it += if(constAddress!=null)
|
|
IRInstructions.loadMemory(Opcode.LOADM, vmDt, inplaceReg, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.loadMemory(Opcode.LOADM, vmDt, inplaceReg, IRMemory.direct(symbol!!))
|
|
if(!codeGen.options.compTarget.cpu.statusBitsOnMultiByteOps)
|
|
it += IRInstructions.compareImmediate(vmDt, inplaceReg, 0)
|
|
it += IRInstructions.branch(Opcode.BSTNE, codeLabel(shortcutLabel))
|
|
}
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.storeMemory(Opcode.STOREM, vmDt, tr.resultReg, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.storeMemory(Opcode.STOREM, vmDt, tr.resultReg, IRMemory.direct(symbol!!)), null)
|
|
result += IRCodeChunk(shortcutLabel, null)
|
|
} else {
|
|
// normal evaluation, it is *likely* shorter and faster because of the simple operands.
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.ORM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.ORM, vmDt, IRMemory.direct(symbol!!), tr.resultReg), null)
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorDivideInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks {
|
|
if(array!=null) {
|
|
if(array.splitWords)
|
|
return operatorDivideInplaceSplitArray(array, operand, signed)
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val eltDt = codeGen.irType(array.type)
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val arrayVariableName = array.variable!!.name
|
|
val divOpcode = if(signed) Opcode.DIVSM else Opcode.DIVM
|
|
val divROpcode = if(signed) Opcode.DIVSR else Opcode.DIVR
|
|
if(eltDt==IRDataType.FLOAT) {
|
|
val constFloat = (operand as? PtNumber)?.number
|
|
if(constIndex!=null) {
|
|
val valueTr = if(constFloat==null) exprGen.translateExpression(operand) else null
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
if(valueTr!=null)
|
|
addToResult(result, valueTr, -1, valueTr.resultFpReg)
|
|
result += IRCodeChunk(null, null).also {
|
|
val valueReg = if(constFloat!=null) {
|
|
val reg = codeGen.registers.next(IRDataType.FLOAT)
|
|
it += IRInstructions.loadFloat(reg, constFloat)
|
|
reg
|
|
} else
|
|
valueTr!!.resultFpReg
|
|
it += IRInstructions.memoryOp(divOpcode, IRDataType.FLOAT, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
return result
|
|
}
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(result, indexTr)
|
|
if(eltSize > 1)
|
|
result += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
val loadReg = codeGen.registers.next(IRDataType.FLOAT)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.FLOAT, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
val valueTr = if(constFloat==null) exprGen.translateExpression(operand) else null
|
|
if(valueTr!=null)
|
|
addToResult(result, valueTr, -1, valueTr.resultFpReg)
|
|
result += IRCodeChunk(null, null).also {
|
|
if(constFloat!=null)
|
|
it += IRInstructions.binaryImmediateFloat(divROpcode, loadReg, constFloat)
|
|
else
|
|
it += IRInstructions.binary(divROpcode, IRDataType.FLOAT, loadReg, valueTr!!.resultFpReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.FLOAT, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
return result
|
|
}
|
|
if(constIndex!=null && constValue!=null) {
|
|
if(constValue!=1) {
|
|
val valueReg = codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(eltDt, valueReg, constValue)
|
|
it += IRInstructions.memoryOp(divOpcode, eltDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constIndex!=null) {
|
|
// Constant index, non-constant value
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
addInstr(result, IRInstructions.memoryOp(divOpcode, eltDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX/DIVR/STOREX
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(result, indexTr)
|
|
if(eltSize > 1) {
|
|
result += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
}
|
|
val loadReg = codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
if(constValue!=null) {
|
|
val constReg = codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(eltDt, constReg, constValue)
|
|
it += IRInstructions.binary(divROpcode, eltDt, loadReg, constReg)
|
|
}
|
|
} else {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(divROpcode, eltDt, loadReg, valueTr.resultReg)
|
|
}
|
|
}
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
val resultVar = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(resultVar, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
if(vmDt==IRDataType.FLOAT) {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, tr, -1, tr.resultFpReg)
|
|
val loadReg = codeGen.registers.next(IRDataType.FLOAT)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.binary(Opcode.DIVR, vmDt, loadReg, tr.resultFpReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
val constVal = (operand as? PtNumber)?.number?.toInt()
|
|
if(constVal!=null) {
|
|
val constReg = codeGen.registers.next(vmDt)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, constReg, constVal)
|
|
val opc = if(signed) Opcode.DIVSR else Opcode.DIVR
|
|
it += IRInstructions.binary(opc, vmDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val opTr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, opTr, opTr.resultReg, -1)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
val opc = if(signed) Opcode.DIVSR else Opcode.DIVR
|
|
it += IRInstructions.binary(opc, vmDt, loadReg, opTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
}
|
|
return resultVar
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constFactorRight = operand as? PtNumber
|
|
if(vmDt==IRDataType.FLOAT) {
|
|
if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
|
val factor = constFactorRight.number
|
|
result += codeGen.divideByConstFloatInplace(constAddress, symbol, factor)
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, -1, tr.resultFpReg)
|
|
val ins = if(signed) {
|
|
if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.DIVSM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultFpReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.DIVSM, vmDt, IRMemory.direct(symbol!!), tr.resultFpReg)
|
|
}
|
|
else {
|
|
if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.DIVM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultFpReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.DIVM, vmDt, IRMemory.direct(symbol!!), tr.resultFpReg)
|
|
}
|
|
addInstr(result, ins, null)
|
|
}
|
|
} else {
|
|
if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
|
val factor = constFactorRight.number.toInt()
|
|
result += codeGen.divideByConstInplace(vmDt, constAddress, symbol, factor, signed)
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
val ins = if(signed) {
|
|
if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.DIVSM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.DIVSM, vmDt, IRMemory.direct(symbol!!), tr.resultReg)
|
|
}
|
|
else {
|
|
if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.DIVM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.DIVM, vmDt, IRMemory.direct(symbol!!), tr.resultReg)
|
|
}
|
|
addInstr(result, ins, null)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorMultiplyInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? {
|
|
if(array!=null) {
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
if(array.splitWords)
|
|
return operatorMultiplyInplaceSplitArray(array, operand)
|
|
val eltDt = codeGen.irType(array.type)
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
if(constIndex!=null && constValue!=null) {
|
|
if(constValue!=1) {
|
|
val arrayVariableName = array.variable!!.name
|
|
val valueReg=codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(eltDt, valueReg, constValue)
|
|
val opcode = if(signed) Opcode.MULSM else Opcode.MULM
|
|
it += IRInstructions.memoryOp(opcode, eltDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
// Non-const cases for non-split arrays
|
|
if(constIndex!=null) {
|
|
// Constant index, non-constant value
|
|
val arrayVariableName = array.variable!!.name
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val opcode = if(signed) Opcode.MULSM else Opcode.MULM
|
|
addInstr(result, IRInstructions.memoryOp(opcode, eltDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX/MULR/STOREX
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(result, indexTr)
|
|
val arrayVariableName = array.variable!!.name
|
|
// Multiply index by element size for LOADX/STOREX
|
|
if(eltSize > 1) {
|
|
result += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
}
|
|
if(constValue!=null) {
|
|
val loadReg = codeGen.registers.next(eltDt)
|
|
val constReg = codeGen.registers.next(eltDt)
|
|
val opcode = if(signed) Opcode.MULSR else Opcode.MULR
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.load(eltDt, constReg, constValue)
|
|
it += IRInstructions.binary(opcode, eltDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(eltDt)
|
|
val opcode = if(signed) Opcode.MULSR else Opcode.MULR
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(opcode, eltDt, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
val resultVar = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(resultVar, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
if(vmDt==IRDataType.FLOAT) {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, tr, -1, tr.resultFpReg)
|
|
val loadReg = codeGen.registers.next(IRDataType.FLOAT)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.binary(Opcode.MULR, vmDt, loadReg, tr.resultFpReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
val constVal = (operand as? PtNumber)?.number?.toInt()
|
|
if(constVal!=null) {
|
|
val constReg = codeGen.registers.next(vmDt)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, constReg, constVal)
|
|
val opc = if(signed) Opcode.MULSR else Opcode.MULR
|
|
it += IRInstructions.binary(opc, vmDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val opTr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, opTr, opTr.resultReg, -1)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
val opc = if(signed) Opcode.MULSR else Opcode.MULR
|
|
it += IRInstructions.binary(opc, vmDt, loadReg, opTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
}
|
|
return resultVar
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constFactorRight = operand as? PtNumber
|
|
if(vmDt==IRDataType.FLOAT) {
|
|
if(constFactorRight!=null) {
|
|
val factor = constFactorRight.number
|
|
result += codeGen.multiplyByConstFloatInplace(constAddress, symbol, factor)
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, -1, tr.resultFpReg)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.MULSM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultFpReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.MULSM, vmDt, IRMemory.direct(symbol!!), tr.resultFpReg)
|
|
, null)
|
|
}
|
|
} else {
|
|
if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
|
val factor = constFactorRight.number.toInt()
|
|
result += codeGen.multiplyByConstInplace(vmDt, signed, constAddress, symbol, factor)
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
val opcode = if(signed) Opcode.MULSM else Opcode.MULM
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(opcode, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(opcode, vmDt, IRMemory.direct(symbol!!), tr.resultReg)
|
|
, null)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorMinusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
|
|
if(array!=null) {
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
if(array.splitWords)
|
|
return operatorMinusInplaceSplitArray(array, operand)
|
|
val eltDt = codeGen.irType(array.type)
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
if(constIndex!=null && constValue!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
|
|
if(constValue==1) {
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.DECM, eltDt, IRMemory.direct(arrayVariableName, constIndex*eltSize)), null)
|
|
} else {
|
|
addInstr(result, IRInstructions.memoryOpImmediate(Opcode.SUBIM, eltDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), constValue), null)
|
|
}
|
|
return result
|
|
}
|
|
// Optimized path for non-const cases
|
|
if(constIndex!=null) {
|
|
// Constant index, non-constant value
|
|
val arrayVariableName = array.variable!!.name
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.SUBM, eltDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX/SUBR/STOREX
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(result, indexTr)
|
|
val arrayVariableName = array.variable!!.name
|
|
// Multiply index by element size for LOADX/STOREX
|
|
if(eltSize > 1) {
|
|
result += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
}
|
|
if(constValue!=null) {
|
|
// Non-constant index, constant value
|
|
val loadReg = codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
val constReg = codeGen.registers.next(eltDt)
|
|
it += IRInstructions.load(eltDt, constReg, constValue)
|
|
it += IRInstructions.binary(Opcode.SUBR, eltDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
// Non-constant index, non-constant value
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.SUBR, eltDt, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
// Memory target: translate address and subtract
|
|
val memResult = mutableListOf<IRCodeChunkBase>()
|
|
|
|
// Check if address is a constant number
|
|
val constMemAddress = memory.address as? PtNumber
|
|
if(constMemAddress!=null) {
|
|
val addr = constMemAddress.number.toUInt()
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(memResult, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, loadReg, IRMemory.direct(addr.toAddress()))
|
|
it += IRInstructions.binary(Opcode.SUBR, IRDataType.BYTE, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, loadReg, IRMemory.direct(addr.toAddress()))
|
|
}
|
|
} else if(operandConstValue==1.0) {
|
|
addInstr(memResult, IRInstructions.memoryOp(Opcode.DECM, IRDataType.BYTE, IRMemory.direct(addr.toAddress())), null)
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, loadReg, IRMemory.direct(addr.toAddress()))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.SUBR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, loadReg, IRMemory.direct(addr.toAddress()))
|
|
}
|
|
}
|
|
return memResult
|
|
}
|
|
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(memResult, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(memResult, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.binary(Opcode.SUBR, IRDataType.BYTE, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
// Constant value, non-const address
|
|
if(operandConstValue==1.0) {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.unary(Opcode.DEC, IRDataType.BYTE, loadReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.SUBR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
}
|
|
return memResult
|
|
}
|
|
|
|
val constValue = (operand as? PtNumber)?.number
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
if(vmDt==IRDataType.FLOAT) {
|
|
if(constValue==1.0) {
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.DECM, vmDt, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.memoryOp(Opcode.DECM, vmDt, IRMemory.direct(symbol!!)), null)
|
|
} else if(constValue!=null) {
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOpImmediateFloat(Opcode.SUBIM, IRMemory.direct(constAddress.toAddress()), constValue)
|
|
else
|
|
IRInstructions.memoryOpImmediateFloat(Opcode.SUBIM, IRMemory.direct(symbol!!), constValue), null)
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, -1, tr.resultFpReg)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.SUBM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultFpReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.SUBM, vmDt, IRMemory.direct(symbol!!), tr.resultFpReg), null)
|
|
}
|
|
} else {
|
|
if(constValue==1.0) {
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.DECM, vmDt, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.memoryOp(Opcode.DECM, vmDt, IRMemory.direct(symbol!!)), null)
|
|
} else if(constValue!=null) {
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOpImmediate(Opcode.SUBIM, vmDt, IRMemory.direct(constAddress.toAddress()), constValue.toInt())
|
|
else
|
|
IRInstructions.memoryOpImmediate(Opcode.SUBIM, vmDt, IRMemory.direct(symbol!!), constValue.toInt()), null)
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.SUBM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.SUBM, vmDt, IRMemory.direct(symbol!!), tr.resultReg), null)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorMultiplyInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): IRCodeChunks? {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
if(constIndex!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
|
|
if(constValue==1) {
|
|
// Multiplying by 1 is a no-op
|
|
return emptyList()
|
|
} else if(constValue!=null) {
|
|
// Handle constant value using CONCAT/MUL/LSIGB/MSIGB
|
|
val wordReg = codeGen.registers.next(IRDataType.WORD)
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
// Load current LSB and MSB
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, msbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
// Concatenate into word register
|
|
it += IRInstructions.concat(IRDataType.BYTE, wordReg, msbReg, lsbReg)
|
|
// Multiply by constant value
|
|
it += IRInstructions.binaryImmediate(Opcode.MUL, IRDataType.WORD, wordReg, constValue)
|
|
// Extract bytes back into NEW registers
|
|
val newLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val newMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, newLsbReg, wordReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, newMsbReg, wordReg)
|
|
// Store back
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newLsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newMsbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
return result
|
|
} else {
|
|
// Non-constant operand: translate expression, then multiply using CONCAT/MUL
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
if(tr.resultReg<0) {
|
|
return null // fallback to slow method
|
|
}
|
|
val wordReg = codeGen.registers.next(IRDataType.WORD)
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
// Load current LSB and MSB from array
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, msbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
// Concatenate into word register
|
|
it += IRInstructions.concat(IRDataType.BYTE, wordReg, msbReg, lsbReg)
|
|
// Multiply by operand value (use MULR for register-to-register)
|
|
it += IRInstructions.binary(Opcode.MULR, IRDataType.WORD, wordReg, tr.resultReg)
|
|
// Extract bytes back into NEW registers
|
|
val newLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val newMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, newLsbReg, wordReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, newMsbReg, wordReg)
|
|
// Store back
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newLsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newMsbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
return null // fallback to slow method for non-constant index
|
|
}
|
|
|
|
private fun operatorMinusInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): IRCodeChunks? {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
if(constIndex!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
|
|
if(constValue==1) {
|
|
val skip = codeGen.createLabelName()
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
if(!codeGen.options.compTarget.cpu.statusBitsOnMultiByteOps)
|
|
it += IRInstructions.compareImmediate(IRDataType.BYTE, lsbReg, 0)
|
|
it += IRInstructions.branch(Opcode.BSTNE, codeLabel(skip))
|
|
it += IRInstructions.memoryOp(Opcode.DECM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
result += IRCodeChunk(skip, null).also {
|
|
it += IRInstructions.memoryOp(Opcode.DECM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
}
|
|
return result
|
|
} else if(constValue!=null) {
|
|
// Handle constant value != 1 using CONCAT/SUB/LSIGB/MSIGB
|
|
val wordReg = codeGen.registers.next(IRDataType.WORD)
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
// Load current LSB and MSB
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, msbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
// Concatenate into word register
|
|
it += IRInstructions.concat(IRDataType.BYTE, wordReg, msbReg, lsbReg)
|
|
// Subtract the constant value
|
|
it += IRInstructions.binaryImmediate(Opcode.SUB, IRDataType.WORD, wordReg, constValue)
|
|
// Extract bytes back into NEW registers
|
|
val newLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val newMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, newLsbReg, wordReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, newMsbReg, wordReg)
|
|
// Store back
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newLsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newMsbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
return result
|
|
} else {
|
|
// Non-constant operand: translate expression, then subtract using CONCAT/SUB
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
if(tr.resultReg<0) {
|
|
return null // fallback to slow method
|
|
}
|
|
val wordReg = codeGen.registers.next(IRDataType.WORD)
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
// Load current LSB and MSB from array
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, msbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
// Concatenate into word register
|
|
it += IRInstructions.concat(IRDataType.BYTE, wordReg, msbReg, lsbReg)
|
|
// Subtract the operand value (use SUBR for register-to-register)
|
|
it += IRInstructions.binary(Opcode.SUBR, IRDataType.WORD, wordReg, tr.resultReg)
|
|
// Extract bytes back into NEW registers
|
|
val newLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val newMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, newLsbReg, wordReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, newMsbReg, wordReg)
|
|
// Store back
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newLsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newMsbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
return null // fallback to slow method for non-constant index
|
|
}
|
|
|
|
private fun operatorPlusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?,
|
|
vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
|
|
if(array!=null) {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
if(array.splitWords)
|
|
return operatorPlusInplaceSplitArray(array, operand)
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
val elementDt = codeGen.irType(array.type)
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
if(constIndex!=null && constValue!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
|
|
if(constValue==1) {
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.INCM, elementDt, IRMemory.direct(arrayVariableName, constIndex*eltSize)), null)
|
|
} else {
|
|
addInstr(result, IRInstructions.memoryOpImmediate(Opcode.ADDIM, elementDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), constValue), null)
|
|
}
|
|
return result
|
|
}
|
|
// Optimized path for non-const cases
|
|
if(constIndex!=null) {
|
|
// Constant index, non-constant value
|
|
val arrayVariableName = array.variable!!.name
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.ADDM, elementDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX/ADDR/STOREX
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(result, indexTr)
|
|
val arrayVariableName = array.variable!!.name
|
|
// Multiply index by element size for LOADX/STOREX
|
|
if(eltSize > 1) {
|
|
result += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
}
|
|
if(constValue!=null) {
|
|
// Non-constant index, constant value
|
|
val loadReg = codeGen.registers.next(elementDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, elementDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
val constReg = codeGen.registers.next(elementDt)
|
|
it += IRInstructions.load(elementDt, constReg, constValue)
|
|
it += IRInstructions.binary(Opcode.ADDR, elementDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, elementDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
// Non-constant index, non-constant value
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(elementDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, elementDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.ADDR, elementDt, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, elementDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
// Memory target: translate address and add
|
|
val memResult = mutableListOf<IRCodeChunkBase>()
|
|
|
|
// Check if address is a constant number
|
|
val constMemAddress = memory.address as? PtNumber
|
|
if(constMemAddress!=null) {
|
|
// Direct constant address - shouldn't normally happen but handle it
|
|
val addr = constMemAddress.number.toUInt()
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(memResult, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, loadReg, IRMemory.direct(addr.toAddress()))
|
|
it += IRInstructions.binary(Opcode.ADDR, IRDataType.BYTE, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, loadReg, IRMemory.direct(addr.toAddress()))
|
|
}
|
|
} else if(operandConstValue==1.0) {
|
|
addInstr(memResult, IRInstructions.memoryOp(Opcode.INCM, IRDataType.BYTE, IRMemory.direct(addr.toAddress())), null)
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, loadReg, IRMemory.direct(addr.toAddress()))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.ADDR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, loadReg, IRMemory.direct(addr.toAddress()))
|
|
}
|
|
}
|
|
return memResult
|
|
}
|
|
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(memResult, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(memResult, valueTr, valueTr.resultReg, -1)
|
|
// LOADI current value, ADD, STOREI back
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.binary(Opcode.ADDR, IRDataType.BYTE, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
// Constant value, non-const address
|
|
if(operandConstValue==1.0) {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.unary(Opcode.INC, IRDataType.BYTE, loadReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.ADDR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
}
|
|
return memResult
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constValue = (operand as? PtNumber)?.number
|
|
|
|
if(vmDt==IRDataType.FLOAT) {
|
|
if(constValue==1.0) {
|
|
addInstr(result, if (constAddress != null)
|
|
IRInstructions.memoryOp(Opcode.INCM, vmDt, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.memoryOp(Opcode.INCM, vmDt, IRMemory.direct(symbol!!)) , null)
|
|
} else if(constValue!=null) {
|
|
addInstr(result, if (constAddress != null)
|
|
IRInstructions.memoryOpImmediateFloat(Opcode.ADDIM, IRMemory.direct(constAddress.toAddress()), constValue)
|
|
else
|
|
IRInstructions.memoryOpImmediateFloat(Opcode.ADDIM, IRMemory.direct(symbol!!), constValue) , null)
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, -1, tr.resultFpReg)
|
|
addInstr(result, if (constAddress != null)
|
|
IRInstructions.memoryOp(Opcode.ADDM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultFpReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.ADDM, vmDt, IRMemory.direct(symbol!!), tr.resultFpReg) , null)
|
|
}
|
|
} else {
|
|
if(constValue==1.0) {
|
|
addInstr(result, if (constAddress != null)
|
|
IRInstructions.memoryOp(Opcode.INCM, vmDt, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.memoryOp(Opcode.INCM, vmDt, IRMemory.direct(symbol!!)) , null)
|
|
} else if(constValue==2.0 && codeGen.options.compTarget.cpu.is6502) {
|
|
result += IRCodeChunk(null, null).also {
|
|
if (constAddress != null) {
|
|
it += IRInstructions.memoryOp(Opcode.INCM, vmDt, IRMemory.direct(constAddress.toAddress()))
|
|
it += IRInstructions.memoryOp(Opcode.INCM, vmDt, IRMemory.direct(constAddress.toAddress()))
|
|
} else {
|
|
val symbolName = symbol!!
|
|
it += IRInstructions.memoryOp(Opcode.INCM, vmDt, IRMemory.direct(symbolName))
|
|
it += IRInstructions.memoryOp(Opcode.INCM, vmDt, IRMemory.direct(symbolName))
|
|
}
|
|
}
|
|
} else if(constValue!=null) {
|
|
addInstr(result, if (constAddress != null)
|
|
IRInstructions.memoryOpImmediate(Opcode.ADDIM, vmDt, IRMemory.direct(constAddress.toAddress()), constValue.toInt())
|
|
else
|
|
IRInstructions.memoryOpImmediate(Opcode.ADDIM, vmDt, IRMemory.direct(symbol!!), constValue.toInt()), null)
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
if (constAddress != null)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.ADDM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg), null)
|
|
else
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.ADDM, vmDt, IRMemory.direct(symbol!!), tr.resultReg) , null)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorPlusInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): IRCodeChunks? {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
if(constIndex!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
|
|
if(constValue==1) {
|
|
val skip = codeGen.createLabelName()
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.memoryOp(Opcode.INCM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
if(!codeGen.options.compTarget.cpu.statusBitsOnMultiByteOps)
|
|
it += IRInstructions.compareImmediate(IRDataType.BYTE, lsbReg, 0)
|
|
it += IRInstructions.branch(Opcode.BSTNE, codeLabel(skip))
|
|
it += IRInstructions.memoryOp(Opcode.INCM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
result += IRCodeChunk(skip, null)
|
|
return result
|
|
} else if(constValue!=null) {
|
|
// Handle constant value != 1 using CONCAT/ADD/LSIGB/MSIGB
|
|
val wordReg = codeGen.registers.next(IRDataType.WORD)
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
// Load current LSB and MSB
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, msbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
// Concatenate into word register
|
|
it += IRInstructions.concat(IRDataType.BYTE, wordReg, msbReg, lsbReg)
|
|
// Add the constant value
|
|
it += IRInstructions.binaryImmediate(Opcode.ADD, IRDataType.WORD, wordReg, constValue)
|
|
// Extract bytes back into NEW registers
|
|
val newLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val newMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, newLsbReg, wordReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, newMsbReg, wordReg)
|
|
// Store back
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newLsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newMsbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
return result
|
|
} else {
|
|
// Non-constant operand: translate expression, then add using CONCAT/ADD
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
if(tr.resultReg<0) {
|
|
return null // fallback to slow method
|
|
}
|
|
val wordReg = codeGen.registers.next(IRDataType.WORD)
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
// Load current LSB and MSB from array
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, msbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
// Concatenate into word register
|
|
it += IRInstructions.concat(IRDataType.BYTE, wordReg, msbReg, lsbReg)
|
|
// Add the operand value (use ADDR for register-to-register)
|
|
it += IRInstructions.binary(Opcode.ADDR, IRDataType.WORD, wordReg, tr.resultReg)
|
|
// Extract bytes back into NEW registers
|
|
val newLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val newMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, newLsbReg, wordReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, newMsbReg, wordReg)
|
|
// Store back
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newLsbReg, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newMsbReg, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
return null // fallback to slow method for non-constant index
|
|
}
|
|
|
|
private fun operatorShiftRightInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? {
|
|
if(array!=null) {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
|
|
if(constIndex!=null && constValue!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
|
|
if(array.splitWords) {
|
|
repeat(constValue) {
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.memoryOp(Opcode.LSRM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
it += IRInstructions.memoryOp(Opcode.ROXRM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
}
|
|
}
|
|
} else {
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
if(constValue==1) {
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.memoryOp(Opcode.LSRM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize))
|
|
}
|
|
} else {
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, constValue and 255)
|
|
it += IRInstructions.memoryOp(Opcode.LSRNM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
// optimized handling for variable index or variable shift count (non-split)
|
|
if(!array.splitWords) {
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
val resultVar = mutableListOf<IRCodeChunkBase>()
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(resultVar, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(resultVar, indexTr)
|
|
if(eltSize > 1)
|
|
resultVar += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(array.variable!!.name, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
val constShift = operand.asConstInteger()
|
|
if(constShift!=null) {
|
|
if(constShift==1) {
|
|
val opc = if(signed) Opcode.ASR else Opcode.LSR
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.unary(opc, vmDt, loadReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(array.variable!!.name, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
val shiftReg = codeGen.registers.next(IRDataType.BYTE)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, shiftReg, constShift and 255)
|
|
val opc = if(signed) Opcode.ASRN else Opcode.LSRN
|
|
it += IRInstructions.binary(opc, vmDt, loadReg, shiftReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(array.variable!!.name, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
} else {
|
|
val shiftTr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, shiftTr, shiftTr.resultReg, -1)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
val opc = if(signed) Opcode.ASRN else Opcode.LSRN
|
|
it += IRInstructions.binary(opc, vmDt, loadReg, shiftTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(array.variable!!.name, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return resultVar
|
|
}
|
|
return null
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
// optimized memory in-place >> with variable address
|
|
val resultVar = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(resultVar, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
val constShift = operand.asConstInteger()
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
if(constShift!=null) {
|
|
if(constShift==1) {
|
|
val opc = if(signed) Opcode.ASR else Opcode.LSR
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.unary(opc, vmDt, loadReg)
|
|
}
|
|
} else {
|
|
val shiftReg = codeGen.registers.next(IRDataType.BYTE)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, shiftReg, constShift and 255)
|
|
val opc = if(signed) Opcode.ASRN else Opcode.LSRN
|
|
it += IRInstructions.binary(opc, vmDt, loadReg, shiftReg)
|
|
}
|
|
}
|
|
} else {
|
|
val shiftTr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, shiftTr, shiftTr.resultReg, -1)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
val opc = if(signed) Opcode.ASRN else Opcode.LSRN
|
|
it += IRInstructions.binary(opc, vmDt, loadReg, shiftTr.resultReg)
|
|
}
|
|
}
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
return resultVar
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
if(codeGen.isOne(operand)) {
|
|
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
|
|
val ins = if(constAddress!=null)
|
|
IRInstructions.memoryOp(opc, vmDt, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.memoryOp(opc, vmDt, IRMemory.direct(symbol!!))
|
|
addInstr(result, ins, null)
|
|
} else {
|
|
val shiftTr = exprGen.translateExpression(operand)
|
|
addToResult(result, shiftTr, shiftTr.resultReg, -1)
|
|
val shiftReg = shiftTr.resultReg
|
|
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
|
|
val ins = if(constAddress!=null)
|
|
IRInstructions.memoryOp(opc, vmDt, IRMemory.direct(constAddress.toAddress()), shiftReg)
|
|
else
|
|
IRInstructions.memoryOp(opc, vmDt, IRMemory.direct(symbol!!), shiftReg)
|
|
addInstr(result, ins, null)
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorShiftLeftInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
|
|
if(array!=null) {
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
|
|
if(constIndex!=null && constValue!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
|
|
if(array.splitWords) {
|
|
repeat(constValue) {
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.memoryOp(Opcode.LSLM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex))
|
|
it += IRInstructions.memoryOp(Opcode.ROXLM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex))
|
|
}
|
|
}
|
|
} else {
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
if(constValue==1) {
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.memoryOp(Opcode.LSLM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize))
|
|
}
|
|
} else {
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, constValue and 255)
|
|
it += IRInstructions.memoryOp(Opcode.LSLNM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(!array.splitWords) {
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
val resultVar = mutableListOf<IRCodeChunkBase>()
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(resultVar, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(resultVar, indexTr)
|
|
if(eltSize > 1)
|
|
resultVar += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(array.variable!!.name, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
val constShift = operand.asConstInteger()
|
|
if(constShift!=null) {
|
|
if(constShift==1) {
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.unary(Opcode.LSL, vmDt, loadReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(array.variable!!.name, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
val shiftReg = codeGen.registers.next(IRDataType.BYTE)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, shiftReg, constShift and 255)
|
|
it += IRInstructions.binary(Opcode.LSLN, vmDt, loadReg, shiftReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(array.variable!!.name, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
} else {
|
|
val shiftTr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, shiftTr, shiftTr.resultReg, -1)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSLN, vmDt, loadReg, shiftTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(array.variable!!.name, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return resultVar
|
|
}
|
|
return null
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
val resultVar = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(resultVar, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
val constShift = operand.asConstInteger()
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
if(constShift!=null) {
|
|
if(constShift==1) {
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.unary(Opcode.LSL, vmDt, loadReg)
|
|
}
|
|
} else {
|
|
val shiftReg = codeGen.registers.next(IRDataType.BYTE)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, shiftReg, constShift and 255)
|
|
it += IRInstructions.binary(Opcode.LSLN, vmDt, loadReg, shiftReg)
|
|
}
|
|
}
|
|
} else {
|
|
val shiftTr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, shiftTr, shiftTr.resultReg, -1)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSLN, vmDt, loadReg, shiftTr.resultReg)
|
|
}
|
|
}
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
return resultVar
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
if(codeGen.isOne(operand)){
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.LSLM, vmDt, IRMemory.direct(constAddress.toAddress()))
|
|
else
|
|
IRInstructions.memoryOp(Opcode.LSLM, vmDt, IRMemory.direct(symbol!!))
|
|
, null)
|
|
} else {
|
|
val shiftTr = exprGen.translateExpression(operand)
|
|
addToResult(result, shiftTr, shiftTr.resultReg, -1)
|
|
val shiftReg = shiftTr.resultReg
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.LSLNM, vmDt, IRMemory.direct(constAddress.toAddress()), shiftReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.LSLNM, vmDt, IRMemory.direct(symbol!!), shiftReg)
|
|
,null)
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorXorInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
|
|
if(array!=null) {
|
|
val arrayVariableName = array.variable!!.name
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
if(constIndex!=null && constValue!=null) {
|
|
if(array.splitWords) {
|
|
val valueRegLsb = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueRegMsb = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(IRDataType.BYTE, valueRegLsb, constValue and 255)
|
|
it += IRInstructions.load(IRDataType.BYTE, valueRegMsb, constValue shr 8)
|
|
it += IRInstructions.memoryOp(Opcode.XORM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex), valueRegLsb)
|
|
it += IRInstructions.memoryOp(Opcode.XORM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex), valueRegMsb)
|
|
}
|
|
} else {
|
|
val valueReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, valueReg, constValue)
|
|
it += IRInstructions.memoryOp(Opcode.XORM, vmDt, IRMemory.direct(arrayVariableName, constIndex*eltSize), valueReg)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
// Non-const cases - handle split and non-split arrays differently
|
|
if(array.splitWords) {
|
|
if(constIndex!=null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
if(valueTr.resultReg < 0) return null
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, lsbReg, valueTr.resultReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, msbReg, valueTr.resultReg)
|
|
it += IRInstructions.memoryOp(Opcode.XORM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_lsb", constIndex), lsbReg)
|
|
it += IRInstructions.memoryOp(Opcode.XORM, IRDataType.BYTE, IRMemory.direct(arrayVariableName+"_msb", constIndex), msbReg)
|
|
}
|
|
return result
|
|
}
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, _) = normalizeArrayIndex(result, indexTr)
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
if(valueTr.resultReg < 0) return null
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, valLsbReg, valueTr.resultReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, valMsbReg, valueTr.resultReg)
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, lsbReg, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, msbReg, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.XORR, IRDataType.BYTE, lsbReg, valLsbReg)
|
|
it += IRInstructions.binary(Opcode.XORR, IRDataType.BYTE, msbReg, valMsbReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, lsbReg, IRMemory.indexed(arrayVariableName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, msbReg, IRMemory.indexed(arrayVariableName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
return result
|
|
}
|
|
// Non-split array cases
|
|
if(constIndex!=null) {
|
|
val arrayVarName = array.variable!!.name
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
addInstr(result, IRInstructions.memoryOp(Opcode.XORM, vmDt, IRMemory.direct(arrayVarName, constIndex*eltSize), valueTr.resultReg), null)
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX/XORR/STOREX
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, _) = normalizeArrayIndex(result, indexTr)
|
|
val arrayVarName2 = array.variable!!.name
|
|
if(constValue!=null) {
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
val constReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.load(vmDt, constReg, constValue)
|
|
it += IRInstructions.binary(Opcode.XORR, vmDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
} else {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.binary(Opcode.XORR, vmDt, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, vmDt, loadReg, IRMemory.indexed(arrayVarName2, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
// Memory target with non-constant address
|
|
val memResult = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(memResult, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val operandConstValue = (operand as? PtNumber)?.number
|
|
|
|
if(operandConstValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(memResult, valueTr, valueTr.resultReg, -1)
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.binary(Opcode.XORR, IRDataType.BYTE, loadReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val loadReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val valueReg = codeGen.registers.next(IRDataType.BYTE)
|
|
memResult += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
it += IRInstructions.load(IRDataType.BYTE, valueReg, operandConstValue.toInt())
|
|
it += IRInstructions.binary(Opcode.XORR, IRDataType.BYTE, loadReg, valueReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
return memResult
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val tr = exprGen.translateExpression(operand)
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
addInstr(result, if(constAddress!=null)
|
|
IRInstructions.memoryOp(Opcode.XORM, vmDt, IRMemory.direct(constAddress.toAddress()), tr.resultReg)
|
|
else
|
|
IRInstructions.memoryOp(Opcode.XORM, vmDt, IRMemory.direct(symbol!!), tr.resultReg)
|
|
,null)
|
|
return result
|
|
}
|
|
|
|
private fun operatorDivideInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression, signed: Boolean): IRCodeChunks {
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val arrayName = array.variable!!.name
|
|
val opcode = if(signed) Opcode.DIVS else Opcode.DIV
|
|
val regOpcode = if(signed) Opcode.DIVSR else Opcode.DIVR
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val indexReg: Int
|
|
|
|
if(constIndex!=null) {
|
|
indexReg = -1
|
|
} else {
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
indexReg = normalizeArrayIndex(result, indexTr).first
|
|
}
|
|
|
|
val wordReg = codeGen.registers.next(IRDataType.WORD)
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
if(constIndex!=null) {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, msbReg, IRMemory.direct(arrayName+"_msb", constIndex))
|
|
} else {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, lsbReg, IRMemory.indexed(arrayName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, msbReg, IRMemory.indexed(arrayName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
it += IRInstructions.concat(IRDataType.BYTE, wordReg, msbReg, lsbReg)
|
|
if(constValue!=null) {
|
|
if(constValue!=1)
|
|
it += IRInstructions.binaryImmediate(opcode, IRDataType.WORD, wordReg, constValue)
|
|
}
|
|
}
|
|
|
|
if(constValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(regOpcode, IRDataType.WORD, wordReg, valueTr.resultReg)
|
|
}
|
|
}
|
|
|
|
val newLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val newMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, newLsbReg, wordReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, newMsbReg, wordReg)
|
|
if(constIndex!=null) {
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newLsbReg, IRMemory.direct(arrayName+"_lsb", constIndex))
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newMsbReg, IRMemory.direct(arrayName+"_msb", constIndex))
|
|
} else {
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, newLsbReg, IRMemory.indexed(arrayName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, newMsbReg, IRMemory.indexed(arrayName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorModuloInplace(symbol: String?, array: PtArrayIndexer?, constAddress: UInt?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks {
|
|
if(array!=null) {
|
|
if(array.splitWords)
|
|
return operatorModuloInplaceSplitArray(array, operand, signed)
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val eltDt = codeGen.irType(array.type)
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val arrayVariableName = array.variable!!.name
|
|
val modOpcode = if(signed) Opcode.MODS else Opcode.MOD
|
|
val modROpcode = if(signed) Opcode.MODSR else Opcode.MODR
|
|
if(constIndex!=null && constValue!=null) {
|
|
val resultReg = codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, eltDt, resultReg, IRMemory.direct(arrayVariableName, constIndex*eltSize))
|
|
it += IRInstructions.binaryImmediate(modOpcode, eltDt, resultReg, constValue)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, eltDt, resultReg, IRMemory.direct(arrayVariableName, constIndex*eltSize))
|
|
}
|
|
return result
|
|
}
|
|
if(constIndex!=null) {
|
|
// Constant index, non-constant value
|
|
val resultReg = codeGen.registers.next(eltDt)
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, eltDt, resultReg, IRMemory.direct(arrayVariableName, constIndex*eltSize))
|
|
it += IRInstructions.binary(modROpcode, eltDt, resultReg, valueTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, eltDt, resultReg, IRMemory.direct(arrayVariableName, constIndex*eltSize))
|
|
}
|
|
return result
|
|
}
|
|
// Non-constant index - use LOADX/MODR/STOREX
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
val (indexReg, indexDt) = normalizeArrayIndex(result, indexTr)
|
|
if(eltSize > 1) {
|
|
result += codeGen.multiplyByConst(indexDt, indexReg, eltSize)
|
|
}
|
|
val loadReg = codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
if(constValue!=null) {
|
|
val constReg = codeGen.registers.next(eltDt)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(eltDt, constReg, constValue)
|
|
it += IRInstructions.binary(modROpcode, eltDt, loadReg, constReg)
|
|
}
|
|
} else {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(modROpcode, eltDt, loadReg, valueTr.resultReg)
|
|
}
|
|
}
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, eltDt, loadReg, IRMemory.indexed(arrayVariableName, indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
return result
|
|
}
|
|
if(constAddress==null && memory!=null) {
|
|
val resultVar = mutableListOf<IRCodeChunkBase>()
|
|
val addrTr = exprGen.translateExpression(memory.address)
|
|
addToResult(resultVar, addrTr, addrTr.resultReg, -1)
|
|
val addressReg = addrTr.resultReg
|
|
val loadReg = codeGen.registers.next(vmDt)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
val modROpcode = if(signed) Opcode.MODSR else Opcode.MODR
|
|
val constVal = (operand as? PtNumber)?.number?.toInt()
|
|
if(constVal!=null) {
|
|
val constReg = codeGen.registers.next(vmDt)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.load(vmDt, constReg, constVal)
|
|
it += IRInstructions.binary(modROpcode, vmDt, loadReg, constReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
} else {
|
|
val opTr = exprGen.translateExpression(operand)
|
|
addToResult(resultVar, opTr, opTr.resultReg, -1)
|
|
resultVar += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(modROpcode, vmDt, loadReg, opTr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREI, vmDt, loadReg, IRMemory.indirect(addressReg, 0))
|
|
}
|
|
}
|
|
return resultVar
|
|
}
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val resultReg = codeGen.registers.next(vmDt)
|
|
val modOpcode = if(signed) Opcode.MODS else Opcode.MOD
|
|
val modROpcode = if(signed) Opcode.MODSR else Opcode.MODR
|
|
if(operand is PtNumber) {
|
|
val number = operand.number.toInt()
|
|
if (constAddress != null) {
|
|
// @(address) = @(address) %= operand
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, vmDt, resultReg, IRMemory.direct(constAddress.toAddress()))
|
|
it += IRInstructions.binaryImmediate(modOpcode, vmDt, resultReg, number)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, vmDt, resultReg, IRMemory.direct(constAddress.toAddress()))
|
|
}
|
|
} else {
|
|
// symbol = symbol %= operand
|
|
result += IRCodeChunk(null, null).also {
|
|
val symbolName = symbol!!
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, vmDt, resultReg, IRMemory.direct(symbolName))
|
|
it += IRInstructions.binaryImmediate(modOpcode, vmDt, resultReg, number)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, vmDt, resultReg, IRMemory.direct(symbolName))
|
|
}
|
|
}
|
|
} else {
|
|
val tr = exprGen.translateExpression(operand)
|
|
result += tr.chunks
|
|
if (constAddress != null) {
|
|
// @(address) = @(address) %= operand
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, vmDt, resultReg, IRMemory.direct(constAddress.toAddress()))
|
|
it += IRInstructions.binary(modROpcode, vmDt, resultReg, tr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, vmDt, resultReg, IRMemory.direct(constAddress.toAddress()))
|
|
}
|
|
} else {
|
|
// symbol = symbol %= operand
|
|
result += IRCodeChunk(null, null).also {
|
|
val symbolName = symbol!!
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, vmDt, resultReg, IRMemory.direct(symbolName))
|
|
it += IRInstructions.binary(modROpcode, vmDt, resultReg, tr.resultReg)
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, vmDt, resultReg, IRMemory.direct(symbolName))
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun operatorModuloInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression, signed: Boolean): IRCodeChunks {
|
|
val constIndex = array.index.asConstInteger()
|
|
val constValue = operand.asConstInteger()
|
|
val arrayName = array.variable!!.name
|
|
val opcode = if(signed) Opcode.MODS else Opcode.MOD
|
|
val regOpcode = if(signed) Opcode.MODSR else Opcode.MODR
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
val indexReg: Int
|
|
|
|
if(constIndex!=null) {
|
|
indexReg = -1
|
|
} else {
|
|
val indexTr = exprGen.translateExpression(array.index)
|
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
|
indexReg = normalizeArrayIndex(result, indexTr).first
|
|
}
|
|
|
|
val wordReg = codeGen.registers.next(IRDataType.WORD)
|
|
val lsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val msbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
if(constIndex!=null) {
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, lsbReg, IRMemory.direct(arrayName+"_lsb", constIndex))
|
|
it += IRInstructions.loadMemory(Opcode.LOADM, IRDataType.BYTE, msbReg, IRMemory.direct(arrayName+"_msb", constIndex))
|
|
} else {
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, lsbReg, IRMemory.indexed(arrayName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.loadMemory(Opcode.LOADX, IRDataType.BYTE, msbReg, IRMemory.indexed(arrayName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
it += IRInstructions.concat(IRDataType.BYTE, wordReg, msbReg, lsbReg)
|
|
if(constValue!=null) {
|
|
it += IRInstructions.binaryImmediate(opcode, IRDataType.WORD, wordReg, constValue)
|
|
}
|
|
}
|
|
|
|
if(constValue==null) {
|
|
val valueTr = exprGen.translateExpression(operand)
|
|
addToResult(result, valueTr, valueTr.resultReg, -1)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(regOpcode, IRDataType.WORD, wordReg, valueTr.resultReg)
|
|
}
|
|
}
|
|
|
|
val newLsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
val newMsbReg = codeGen.registers.next(IRDataType.BYTE)
|
|
result += IRCodeChunk(null, null).also {
|
|
it += IRInstructions.binary(Opcode.LSIGB, IRDataType.WORD, newLsbReg, wordReg)
|
|
it += IRInstructions.binary(Opcode.MSIGB, IRDataType.WORD, newMsbReg, wordReg)
|
|
if(constIndex!=null) {
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newLsbReg, IRMemory.direct(arrayName+"_lsb", constIndex))
|
|
it += IRInstructions.storeMemory(Opcode.STOREM, IRDataType.BYTE, newMsbReg, IRMemory.direct(arrayName+"_msb", constIndex))
|
|
} else {
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, newLsbReg, IRMemory.indexed(arrayName+"_lsb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
it += IRInstructions.storeMemory(Opcode.STOREX, IRDataType.BYTE, newMsbReg, IRMemory.indexed(arrayName+"_msb", indexReg, codeGen.options.compTarget.indexRegType))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun tryFoldStructArrayDirectWrite(addressExpr: PtExpression, zero: Boolean, valueReg: Int, targetDt: IRDataType, result: MutableList<IRCodeChunkBase>): Boolean {
|
|
val info = extractStructArrayIndexInfo(addressExpr, codeGen) ?: return false
|
|
val (idxCode, indexReg) = codeGen.loadIndexReg(info.idxExpr, info.structSize, codeGen.wordArrayIndex, false)
|
|
result += idxCode
|
|
if(zero) {
|
|
result += IRCodeChunk(null, null).also {
|
|
if(info.fieldOffset==0) it += IRInstructions.storeZero(Opcode.STOREZX, targetDt, IRMemory.indexed(info.arrayName, indexReg, codeGen.options.compTarget.indexRegType, scale=info.structSize))
|
|
else it += IRInstructions.storeZero(Opcode.STOREZX, targetDt, IRMemory.indexed(info.arrayName, indexReg, codeGen.options.compTarget.indexRegType, scale=info.structSize, displacement=info.fieldOffset))
|
|
}
|
|
} else {
|
|
if(valueReg<0) return false
|
|
result += IRCodeChunk(null, null).also {
|
|
if(info.fieldOffset==0) it += IRInstructions.storeMemory(Opcode.STOREX, targetDt, valueReg, IRMemory.indexed(info.arrayName, indexReg, codeGen.options.compTarget.indexRegType, scale=info.structSize))
|
|
else it += IRInstructions.storeMemory(Opcode.STOREX, targetDt, valueReg, IRMemory.indexed(info.arrayName, indexReg, codeGen.options.compTarget.indexRegType, scale=info.structSize, displacement=info.fieldOffset))
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
}
|