diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index df422951e..6b3562d19 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -1,8 +1,5 @@ package prog8.codegen.intermediate -import com.github.michaelbull.result.Ok -import com.github.michaelbull.result.Result -import com.github.michaelbull.result.getOrElse import prog8.code.ast.* import prog8.code.core.* import prog8.intermediate.* @@ -31,31 +28,31 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val array = target.array val value = augAssign.value val signed = target.type in SignedDatatypes - val result: Result = when(augAssign.operator) { - "+=" -> expressionEval.operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value) - "-=" -> expressionEval.operatorMinusInplace(symbol, array, constAddress, memTarget, targetDt, value) - "*=" -> expressionEval.operatorMultiplyInplace(symbol, array, constAddress, memTarget, targetDt, value) - "/=" -> expressionEval.operatorDivideInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) - "|=" -> expressionEval.operatorOrInplace(symbol, array, constAddress, memTarget, targetDt, value) - "or=" -> expressionEval.operatorLogicalOrInplace(symbol, array, constAddress, memTarget, targetDt, value) - "&=" -> expressionEval.operatorAndInplace(symbol, array, constAddress, memTarget, targetDt, value) - "and=" -> expressionEval.operatorLogicalAndInplace(symbol, array, constAddress, memTarget, targetDt, value) - "^=", "xor=" -> expressionEval.operatorXorInplace(symbol, array, constAddress, memTarget, targetDt, value) - "<<=" -> expressionEval.operatorShiftLeftInplace(symbol, array, constAddress, memTarget, targetDt, value) - ">>=" -> expressionEval.operatorShiftRightInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) - "%=" -> expressionEval.operatorModuloInplace(symbol, array, constAddress, memTarget, targetDt, value) - "==" -> expressionEval.operatorEqualsInplace(symbol, array, constAddress, memTarget, targetDt, value) - "!=" -> expressionEval.operatorNotEqualsInplace(symbol, array, constAddress, memTarget, targetDt, value) - "<" -> expressionEval.operatorLessInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) - ">" -> expressionEval.operatorGreaterInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) - "<=" -> expressionEval.operatorLessEqualInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) - ">=" -> expressionEval.operatorGreaterEqualInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) + val result = when(augAssign.operator) { + "+=" -> operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value) + "-=" -> operatorMinusInplace(symbol, array, constAddress, memTarget, targetDt, value) + "*=" -> operatorMultiplyInplace(symbol, array, constAddress, memTarget, targetDt, value) + "/=" -> 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) + "==" -> operatorEqualsInplace(symbol, array, constAddress, memTarget, targetDt, value) + "!=" -> operatorNotEqualsInplace(symbol, array, constAddress, memTarget, targetDt, value) + "<" -> operatorLessInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) + ">" -> operatorGreaterInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) + "<=" -> operatorLessEqualInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) + ">=" -> operatorGreaterEqualInplace(symbol, array, constAddress, memTarget, targetDt, value, signed) in PrefixOperators -> inplacePrefix(augAssign.operator, symbol, array, constAddress, memTarget, targetDt) else -> throw AssemblyError("invalid augmented assign operator ${augAssign.operator}") } - val chunks = result.getOrElse { fallbackAssign(augAssign) } + val chunks = if(result!=null) result else fallbackAssign(augAssign) chunks.filterIsInstance().firstOrNull()?.appendSrcPosition(augAssign.position) return chunks } @@ -84,12 +81,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express return translateRegularAssign(normalAssign) } - private fun inplacePrefix(operator: String, symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType): Result { + private fun inplacePrefix(operator: String, symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType): IRCodeChunks? { if(operator=="+") - return Ok(emptyList()) + return emptyList() if(array!=null) - return Ok(inplacePrefixArray(operator, array)) + return inplacePrefixArray(operator, array) val result = mutableListOf() if(constAddress==null && memory!=null) { @@ -126,7 +123,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express else -> throw AssemblyError("weird prefix operator") } } - return Ok(result) + return result } private fun inplacePrefixArray(operator: String, array: PtArrayIndexer): IRCodeChunks { @@ -456,4 +453,905 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express addToResult(result, tr, tr.resultReg, -1) return Pair(result, tr.resultReg) } + + private fun operatorAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + val eltSize = codeGen.program.memsizer.memorySize(array.type) + if(constIndex!=null && constValue!=null) { + if(array.splitWords) { + val valueRegLsb = codeGen.registers.nextFree() + val valueRegMsb = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + } else { + val valueReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return result + } + return null // TODO("inplace word array &") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place &") + + val result = mutableListOf() + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol),null) + return result + } + + private fun operatorLogicalAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + val eltSize = codeGen.program.memsizer.memorySize(array.type) + if(constIndex!=null && constValue!=null) { + if(array.splitWords) { + val valueRegLsb = codeGen.registers.nextFree() + val valueRegMsb = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + } else { + val valueReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return result + } + return null // TODO("inplace word array and") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place and") + + val result = mutableListOf() + val tr = expressionEval.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.nextFree() + val shortcutLabel = codeGen.createLabelName() + result += IRCodeChunk(null, null).also { + it += if(constAddress!=null) + IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, address = constAddress) + else + IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, labelSymbol = symbol) + it += IRInstruction(Opcode.BSTEQ, labelSymbol = shortcutLabel) + } + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = 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) + IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol),null) + } + return result + } + + private fun operatorOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + val eltSize = codeGen.program.memsizer.memorySize(array.type) + if(constIndex!=null && constValue!=null) { + if(array.splitWords) { + val valueRegLsb = codeGen.registers.nextFree() + val valueRegMsb = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + } else { + val valueReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return result + } + return null // TODO("inplace word array |") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place |") + + val result = mutableListOf() + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol), null) + return result + } + + private fun operatorLogicalOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + val eltSize = codeGen.program.memsizer.memorySize(array.type) + if(constIndex!=null && constValue!=null) { + if(array.splitWords) { + val valueRegLsb = codeGen.registers.nextFree() + val valueRegMsb = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + } else { + val valueReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return result + } + return null // TODO("inplace word array or") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place or"") + + val result = mutableListOf() + val tr = expressionEval.translateExpression(operand) + if(!operand.isSimple()) { + // short-circuit LEFT or RIGHT --> if LEFT then LEFT else RIGHT + val inplaceReg = codeGen.registers.nextFree() + val shortcutLabel = codeGen.createLabelName() + result += IRCodeChunk(null, null).also { + it += if(constAddress!=null) + IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, address = constAddress) + else + IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, labelSymbol = symbol) + it += IRInstruction(Opcode.BSTNE, labelSymbol = shortcutLabel) + } + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = 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) + IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol), null) + } + return result + } + + private fun operatorDivideInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? { + if(array!=null) { + TODO("/ in array") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place /"") + + val result = mutableListOf() + val constFactorRight = operand as? PtNumber + if(vmDt==IRDataType.FLOAT) { + if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + val factor = constFactorRight.number + result += codeGen.divideByConstFloatInplace(constAddress, symbol, factor) + } else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, -1, tr.resultFpReg) + val ins = if(signed) { + if(constAddress!=null) + IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress) + else + IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) + } + else { + if(constAddress!=null) + IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress) + else + IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) + } + addInstr(result, ins, null) + } + } else { + if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + val factor = constFactorRight.number.toInt() + result += codeGen.divideByConstInplace(vmDt, constAddress, symbol, factor, signed) + } else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + val ins = if(signed) { + if(constAddress!=null) + IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) + } + else { + if(constAddress!=null) + IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) + } + addInstr(result, ins, null) + } + } + return result + } + + private fun operatorMultiplyInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + TODO("* in array") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place *"") + + val result = mutableListOf() + 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 = expressionEval.translateExpression(operand) + addToResult(result, tr, -1, tr.resultFpReg) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress) + else + IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) + , null) + } + } else { + if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + val factor = constFactorRight.number.toInt() + result += codeGen.multiplyByConstInplace(vmDt, constAddress, symbol, factor) + } else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + , null) + } + } + return result + } + + private fun operatorMinusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + val eltSize = codeGen.program.memsizer.memorySize(array.type) + val result = mutableListOf() + if(array.splitWords) + return operatorMinusInplaceSplitArray(array, operand) + val eltDt = irType(array.type) + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + if(constIndex!=null && constValue!=null) { + if(constValue==1) { + addInstr(result, IRInstruction(Opcode.DECM, eltDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null) + } else { + val valueReg=codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, eltDt, reg1=valueReg, immediate = constValue) + it += IRInstruction(Opcode.SUBM, eltDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return result + } + return null // TODO("inplace array -") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place -"") + + val result = mutableListOf() + if(vmDt==IRDataType.FLOAT) { + if((operand as? PtNumber)?.number==1.0) { + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.DECM, vmDt, address = constAddress) + else + IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol) + , null) + } + else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, -1, tr.resultFpReg) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, address = constAddress) + else + IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol) + , null) + } + } else { + if((operand as? PtNumber)?.number==1.0) { + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.DECM, vmDt, address = constAddress) + else + IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol) + , null) + } + else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + , null) + } + } + return result + } + + private fun operatorMinusInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): IRCodeChunks? { + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + if(constIndex!=null) { + val skip = codeGen.createLabelName() + if(constValue==1) { + val lsbReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = lsbReg, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.BSTNE, labelSymbol = skip) + it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + result += IRCodeChunk(skip, null).also { + it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + } + return result + } else { + return null // TODO("inplace split word array +") + } + } + return null // TODO("inplace split word array +") + } + + private fun operatorPlusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + val result = mutableListOf() + if(array.splitWords) + return operatorPlusInplaceSplitArray(array, operand) + val eltSize = codeGen.program.memsizer.memorySize(array.type) + val elementDt = irType(array.type) + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + if(constIndex!=null && constValue!=null) { + if(constValue==1) { + addInstr(result, IRInstruction(Opcode.INCM, elementDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null) + } else { + val valueReg=codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, elementDt, reg1=valueReg, immediate = constValue) + it += IRInstruction(Opcode.ADDM, elementDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return result + } + return null // TODO("inplace array +") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place +"") + + val result = mutableListOf() + if(vmDt==IRDataType.FLOAT) { + if((operand as? PtNumber)?.number==1.0) { + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.INCM, vmDt, address = constAddress) + else + IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) + , null) + } + else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, -1, tr.resultFpReg) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, address = constAddress) + else + IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol) + , null) + } + } else { + if((operand as? PtNumber)?.number==1.0) { + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.INCM, vmDt, address = constAddress) + else + IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) + , null) + } + else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + , null) + } + } + return result + } + + private fun operatorPlusInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): IRCodeChunks? { + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + if(constIndex!=null) { + val skip = codeGen.createLabelName() + if(constValue==1) { + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.BSTNE, labelSymbol = skip) + it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + result += IRCodeChunk(skip, null) + return result + } else { + return null // TODO("inplace split word array +") + } + } + return null // TODO("inplace split word array +") + } + + private fun operatorShiftRightInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? { + if(array!=null) { + TODO(">> in array") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place >>"") + + val result = mutableListOf() + if(codeGen.isOne(operand)) { + val opc = if (signed) Opcode.ASRM else Opcode.LSRM + val ins = if(constAddress!=null) + IRInstruction(opc, vmDt, address = constAddress) + else + IRInstruction(opc, vmDt, labelSymbol = symbol) + addInstr(result, ins, null) + } else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM + val ins = if(constAddress!=null) + IRInstruction(opc, vmDt, reg1 = tr.resultReg, address = constAddress) + else + IRInstruction(opc, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) + addInstr(result, ins, null) + } + return result + } + + private fun operatorShiftLeftInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + TODO("<< in array") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place <<"") + + val result = mutableListOf() + if(codeGen.isOne(operand)){ + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.LSLM, vmDt, address = constAddress) + else + IRInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol) + , null) + } else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + ,null) + } + return result + } + + private fun operatorXorInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + val eltSize = codeGen.program.memsizer.memorySize(array.type) + if(constIndex!=null && constValue!=null) { + if(array.splitWords) { + val valueRegLsb = codeGen.registers.nextFree() + val valueRegMsb = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) + it += IRInstruction(Opcode.XORM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.XORM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + } else { + val valueReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) + it += IRInstruction(Opcode.XORM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return result + } + return null // TODO("inplace word array xor") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place xor"") + + val result = mutableListOf() + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + addInstr(result, if(constAddress!=null) + IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + ,null) + return result + } + + private fun operatorModuloInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) { + TODO("% in array") + } + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place %"") + + val result = mutableListOf() + val resultReg = codeGen.registers.nextFree() + if(operand is PtNumber) { + val number = operand.number.toInt() + if (constAddress != null) { + // @(address) = @(address) %= operand + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, address = constAddress) + it += IRInstruction(Opcode.MOD, vmDt, reg1 = resultReg, immediate = number) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, address = constAddress) + } + } else { + // symbol = symbol %= operand + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, labelSymbol = symbol) + it += IRInstruction(Opcode.MOD, vmDt, reg1 = resultReg, immediate = number) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, labelSymbol = symbol) + } + } + } else { + val tr = expressionEval.translateExpression(operand) + result += tr.chunks + if (constAddress != null) { + // @(address) = @(address) %= operand + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, address = constAddress) + it += IRInstruction(Opcode.MODR, vmDt, reg1 = resultReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, address = constAddress) + } + } else { + // symbol = symbol %= operand + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, labelSymbol = symbol) + it += IRInstruction(Opcode.MODR, vmDt, reg1 = resultReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, labelSymbol = symbol) + } + } + } + return result + } + + private fun operatorEqualsInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) + return createInplaceArrayComparison(array, operand, "==") + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place compare"") + + val chunks = if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(constAddress, symbol, operand, Opcode.SEQ) + } else { + createInplaceComparison(constAddress, symbol, vmDt, operand, Opcode.SEQ) + } + return chunks + } + + private fun operatorNotEqualsInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { + if(array!=null) + return createInplaceArrayComparison(array, operand, "!=") + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place compare"") + + val chunks = if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(constAddress, symbol, operand, Opcode.SNE) + } else { + createInplaceComparison(constAddress, symbol, vmDt, operand, Opcode.SNE) + } + return chunks + } + + private fun operatorGreaterInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? { + if(array!=null) + return createInplaceArrayComparison(array, operand, ">") + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place compare"") + + val opcode = if(signed) Opcode.SGTS else Opcode.SGT + val chunks = if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(constAddress, symbol, operand, opcode) + } else { + createInplaceComparison(constAddress, symbol, vmDt, operand, opcode) + } + return chunks + } + + private fun operatorLessInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? { + if(array!=null) + return createInplaceArrayComparison(array, operand, "<") + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place compare"") + + val opcode = if(signed) Opcode.SLTS else Opcode.SLT + val chunks = if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(constAddress, symbol, operand, opcode) + } else { + createInplaceComparison(constAddress, symbol, vmDt, operand, opcode) + } + return chunks + } + + private fun operatorGreaterEqualInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? { + if(array!=null) + return createInplaceArrayComparison(array, operand, ">=") + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place compare"") + + val opcode = if(signed) Opcode.SGES else Opcode.SGE + val chunks = if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(constAddress, symbol, operand, opcode) + } else { + createInplaceComparison(constAddress, symbol, vmDt, operand, opcode) + } + return chunks + } + + private fun operatorLessEqualInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? { + if(array!=null) + return createInplaceArrayComparison(array, operand, "<=") + if(constAddress==null && memory!=null) + return null // TODO("optimized memory in-place compare"") + + val opcode = if(signed) Opcode.SLES else Opcode.SLE + val chunks = if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(constAddress, symbol, operand, opcode) + } else { + createInplaceComparison(constAddress, symbol, vmDt, operand, opcode) + } + return chunks + } + + private fun createInplaceComparison( + constAddress: Int?, + symbol: String?, + vmDt: IRDataType, + operand: PtExpression, + compareAndSetOpcode: Opcode + ): MutableList { + val result = mutableListOf() + val valueReg = codeGen.registers.nextFree() + val cmpResultReg = codeGen.registers.nextFree() + if(operand is PtNumber || operand is PtBool) { + + if(operand is PtNumber && operand.number==0.0 && compareAndSetOpcode in arrayOf(Opcode.SEQ, Opcode.SNE)) { + // ==0 or !=0 optimized case + val compareAndSetOpcodeZero = if(compareAndSetOpcode==Opcode.SEQ) Opcode.SZ else Opcode.SNZ + if (constAddress != null) { + // in-place modify a memory location + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = constAddress) + it += IRInstruction(compareAndSetOpcodeZero, vmDt, reg1 = cmpResultReg, reg2 = valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress) + } + } else { + // in-place modify a symbol (variable) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(compareAndSetOpcodeZero, vmDt, reg1=cmpResultReg, reg2 = valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) + } + } + return result + } + + // compare against number that is not 0 + val numberReg = codeGen.registers.nextFree() + val value = if(operand is PtNumber) operand.number.toInt() else if(operand is PtBool) operand.asInt() else throw AssemblyError("wrong operand type") + if (constAddress != null) { + // in-place modify a memory location + val innervalue = if(operand is PtNumber) operand.number.toInt() else if(operand is PtBool) operand.asInt() else throw AssemblyError("wrong operand type") + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = constAddress) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=numberReg, immediate = innervalue) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = cmpResultReg, reg2 = valueReg, reg3 = numberReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress) + } + } else { + // in-place modify a symbol (variable) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=numberReg, immediate = value) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = numberReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) + } + } + } else { + val tr = expressionEval.translateExpression(operand) + addToResult(result, tr, tr.resultReg, -1) + if (constAddress != null) { + // in-place modify a memory location + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = constAddress) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress) + } + } else { + // in-place modify a symbol (variable) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) + } + } + } + return result + } + + private fun createInplaceFloatComparison( + constAddress: Int?, + symbol: String?, + operand: PtExpression, + compareAndSetOpcode: Opcode + ): MutableList { + val result = mutableListOf() + val valueReg = codeGen.registers.nextFreeFloat() + val cmpReg = codeGen.registers.nextFree() + val zeroReg = codeGen.registers.nextFree() + if(operand is PtNumber) { + val numberReg = codeGen.registers.nextFreeFloat() + val cmpResultReg = codeGen.registers.nextFree() + if (constAddress != null) { + // in-place modify a memory location + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress) + it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number) + it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = numberReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) + it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress) + } + } else { + // in-place modify a symbol (variable) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number) + it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = numberReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) + it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) + } + } + } else { + val tr = expressionEval.translateExpression(operand) + val cmpResultReg = codeGen.registers.nextFree() + addToResult(result, tr, -1, tr.resultFpReg) + if (constAddress != null) { + // in-place modify a memory location + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress) + it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = tr.resultFpReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) + it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress) + } + } else { + // in-place modify a symbol (variable) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = tr.resultFpReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) + it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) + } + } + } + return result + } + + private fun createInplaceArrayComparison(array: PtArrayIndexer, value: PtExpression, comparisonOperator: String): IRCodeChunks? { + if(array.type==DataType.FLOAT) + return null // TODO("optimized in-place compare on float arrays")) // TODO? + + val eltSize = codeGen.program.memsizer.memorySize(array.type) + val result = mutableListOf() + if(array.splitWords) + TODO("inplace compare for split word array") + val vmDt = irType(array.type) + val constIndex = array.index.asConstInteger() + val constValue = value.asConstInteger() + val cmpResultReg = codeGen.registers.nextFree() + if(constIndex!=null) { + if(constValue==0) { + // comparison against zero. + val valueReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + when(comparisonOperator) { + "==" -> it += IRInstruction(Opcode.SZ, vmDt, reg1=cmpResultReg, reg2=valueReg) + "!=" -> it += IRInstruction(Opcode.SNZ, vmDt, reg1=cmpResultReg, reg2=valueReg) + "<" -> return null // TODO("array <0 inplace")) // TODO? + "<=" -> return null // TODO("array <=0 inplace")) // TODO? + ">" -> return null // TODO("array >0 inplace")) // TODO? + ">=" -> return null // TODO("array >=0 inplace")) // TODO? + else -> throw AssemblyError("invalid operator") + } + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + return result + } else { + return null // TODO("compare against non-zero value")) + } + } else { + if(constValue==0) { + // comparison against zero. + val valueReg = codeGen.registers.nextFree() + val indexTr = expressionEval.translateExpression(array.index) + addToResult(result, indexTr, indexTr.resultReg, -1) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADX, vmDt, reg1=valueReg, reg2=indexTr.resultReg, labelSymbol = array.variable.name) + when(comparisonOperator) { + "==" -> it += IRInstruction(Opcode.SZ, vmDt, reg1=cmpResultReg, reg2=valueReg) + "!=" -> it += IRInstruction(Opcode.SNZ, vmDt, reg1=cmpResultReg, reg2=valueReg) + "<" -> return null // TODO("array <0 inplace")) // TODO? + "<=" -> return null // TODO("array <=0 inplace")) // TODO? + ">" -> return null // TODO("array >0 inplace")) // TODO? + ">=" -> return null // TODO("array >=0 inplace")) // TODO? + else -> throw AssemblyError("invalid operator") + } + it += IRInstruction(Opcode.STOREX, vmDt, reg1=valueReg, reg2=indexTr.resultReg, labelSymbol = array.variable.name) + } + return result + } + else + return null // TODO("compare against non-zero value")) + } + } + } \ No newline at end of file diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 9a15cd2b6..fe192814e 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -1,8 +1,5 @@ package prog8.codegen.intermediate -import com.github.michaelbull.result.Err -import com.github.michaelbull.result.Ok -import com.github.michaelbull.result.Result import prog8.code.StRomSub import prog8.code.StSub import prog8.code.ast.* @@ -1057,907 +1054,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } } - - internal fun operatorAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - val result = mutableListOf() - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) - if(constIndex!=null && constValue!=null) { - if(array.splitWords) { - val valueRegLsb = codeGen.registers.nextFree() - val valueRegMsb = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) - it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) - it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) - } - } else { - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) - it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - } - } - return Ok(result) - } - return Err(NotImplementedError("inplace word array &")) // TODO? - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place &")) // TODO - - val result = mutableListOf() - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol),null) - return Ok(result) - } - - internal fun operatorLogicalAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - val result = mutableListOf() - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) - if(constIndex!=null && constValue!=null) { - if(array.splitWords) { - val valueRegLsb = codeGen.registers.nextFree() - val valueRegMsb = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) - it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) - it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) - } - } else { - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) - it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - } - } - return Ok(result) - } - return Err(NotImplementedError("inplace word array and")) // TODO? - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place and")) // TODO - - val result = mutableListOf() - val tr = 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.nextFree() - val shortcutLabel = codeGen.createLabelName() - result += IRCodeChunk(null, null).also { - it += if(constAddress!=null) - IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, address = constAddress) - else - IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, labelSymbol = symbol) - it += IRInstruction(Opcode.BSTEQ, labelSymbol = shortcutLabel) - } - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = 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) - IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol),null) - } - return Ok(result) - } - - internal fun operatorOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - val result = mutableListOf() - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) - if(constIndex!=null && constValue!=null) { - if(array.splitWords) { - val valueRegLsb = codeGen.registers.nextFree() - val valueRegMsb = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) - it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) - it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) - } - } else { - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) - it += IRInstruction(Opcode.ORM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - } - } - return Ok(result) - } - return Err(NotImplementedError("inplace word array |")) // TODO? - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place |")) // TODO - - val result = mutableListOf() - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol), null) - return Ok(result) - } - - internal fun operatorLogicalOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - val result = mutableListOf() - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) - if(constIndex!=null && constValue!=null) { - if(array.splitWords) { - val valueRegLsb = codeGen.registers.nextFree() - val valueRegMsb = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) - it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) - it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) - } - } else { - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) - it += IRInstruction(Opcode.ORM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - } - } - return Ok(result) - } - return Err(NotImplementedError("inplace word array or")) // TODO? - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place or")) // TODO - - val result = mutableListOf() - val tr = translateExpression(operand) - if(!operand.isSimple()) { - // short-circuit LEFT or RIGHT --> if LEFT then LEFT else RIGHT - val inplaceReg = codeGen.registers.nextFree() - val shortcutLabel = codeGen.createLabelName() - result += IRCodeChunk(null, null).also { - it += if(constAddress!=null) - IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, address = constAddress) - else - IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, labelSymbol = symbol) - it += IRInstruction(Opcode.BSTNE, labelSymbol = shortcutLabel) - } - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = 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) - IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol), null) - } - return Ok(result) - } - - internal fun operatorDivideInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result { - if(array!=null) { - TODO("/ in array") - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place /")) // TODO - - val result = mutableListOf() - val constFactorRight = operand as? PtNumber - if(vmDt==IRDataType.FLOAT) { - if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { - val factor = constFactorRight.number - result += codeGen.divideByConstFloatInplace(constAddress, symbol, factor) - } else { - val tr = translateExpression(operand) - addToResult(result, tr, -1, tr.resultFpReg) - val ins = if(signed) { - if(constAddress!=null) - IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress) - else - IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) - } - else { - if(constAddress!=null) - IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress) - else - IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) - } - addInstr(result, ins, null) - } - } else { - if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { - val factor = constFactorRight.number.toInt() - result += codeGen.divideByConstInplace(vmDt, constAddress, symbol, factor, signed) - } else { - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - val ins = if(signed) { - if(constAddress!=null) - IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) - } - else { - if(constAddress!=null) - IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) - } - addInstr(result, ins, null) - } - } - return Ok(result) - } - - internal fun operatorMultiplyInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - TODO("* in array") - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place *")) // TODO - - val result = mutableListOf() - 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 = translateExpression(operand) - addToResult(result, tr, -1, tr.resultFpReg) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress) - else - IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) - , null) - } - } else { - if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { - val factor = constFactorRight.number.toInt() - result += codeGen.multiplyByConstInplace(vmDt, constAddress, symbol, factor) - } else { - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) - , null) - } - } - return Ok(result) - } - - internal fun operatorMinusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - val eltSize = codeGen.program.memsizer.memorySize(array.type) - val result = mutableListOf() - if(array.splitWords) - return operatorMinusInplaceSplitArray(array, operand) - val eltDt = irType(array.type) - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - if(constIndex!=null && constValue!=null) { - if(constValue==1) { - addInstr(result, IRInstruction(Opcode.DECM, eltDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null) - } else { - val valueReg=codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, eltDt, reg1=valueReg, immediate = constValue) - it += IRInstruction(Opcode.SUBM, eltDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - } - } - return Ok(result) - } - return Err(NotImplementedError("inplace array -")) // TODO? - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place -")) // TODO - - val result = mutableListOf() - if(vmDt==IRDataType.FLOAT) { - if((operand as? PtNumber)?.number==1.0) { - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.DECM, vmDt, address = constAddress) - else - IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol) - , null) - } - else { - val tr = translateExpression(operand) - addToResult(result, tr, -1, tr.resultFpReg) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, address = constAddress) - else - IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol) - , null) - } - } else { - if((operand as? PtNumber)?.number==1.0) { - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.DECM, vmDt, address = constAddress) - else - IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol) - , null) - } - else { - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) - , null) - } - } - return Ok(result) - } - - private fun operatorMinusInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): Result { - val result = mutableListOf() - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - if(constIndex!=null) { - val skip = codeGen.createLabelName() - if(constValue==1) { - val lsbReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = lsbReg, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) - it += IRInstruction(Opcode.BSTNE, labelSymbol = skip) - it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) - } - result += IRCodeChunk(skip, null).also { - it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) - } - return Ok(result) - } else { - return Err(NotImplementedError("inplace split word array +")) // TODO? - } - } - return Err(NotImplementedError("inplace split word array +")) // TODO? - } - - internal fun operatorPlusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - val result = mutableListOf() - if(array.splitWords) - return operatorPlusInplaceSplitArray(array, operand) - val eltSize = codeGen.program.memsizer.memorySize(array.type) - val elementDt = irType(array.type) - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - if(constIndex!=null && constValue!=null) { - if(constValue==1) { - addInstr(result, IRInstruction(Opcode.INCM, elementDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null) - } else { - val valueReg=codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, elementDt, reg1=valueReg, immediate = constValue) - it += IRInstruction(Opcode.ADDM, elementDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - } - } - return Ok(result) - } - return Err(NotImplementedError("inplace array +")) // TODO? - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place +")) // TODO - - val result = mutableListOf() - if(vmDt==IRDataType.FLOAT) { - if((operand as? PtNumber)?.number==1.0) { - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.INCM, vmDt, address = constAddress) - else - IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) - , null) - } - else { - val tr = translateExpression(operand) - addToResult(result, tr, -1, tr.resultFpReg) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, address = constAddress) - else - IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol) - , null) - } - } else { - if((operand as? PtNumber)?.number==1.0) { - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.INCM, vmDt, address = constAddress) - else - IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) - , null) - } - else { - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) - , null) - } - } - return Ok(result) - } - - private fun operatorPlusInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): Result { - val result = mutableListOf() - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - if(constIndex!=null) { - val skip = codeGen.createLabelName() - if(constValue==1) { - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) - it += IRInstruction(Opcode.BSTNE, labelSymbol = skip) - it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) - } - result += IRCodeChunk(skip, null) - return Ok(result) - } else { - return Err(NotImplementedError("inplace split word array +")) // TODO? - } - } - return Err(NotImplementedError("inplace split word array +")) // TODO? - } - - internal fun operatorShiftRightInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result { - if(array!=null) { - TODO(">> in array") - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place >>")) // TODO - - val result = mutableListOf() - if(codeGen.isOne(operand)) { - val opc = if (signed) Opcode.ASRM else Opcode.LSRM - val ins = if(constAddress!=null) - IRInstruction(opc, vmDt, address = constAddress) - else - IRInstruction(opc, vmDt, labelSymbol = symbol) - addInstr(result, ins, null) - } else { - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM - val ins = if(constAddress!=null) - IRInstruction(opc, vmDt, reg1 = tr.resultReg, address = constAddress) - else - IRInstruction(opc, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) - addInstr(result, ins, null) - } - return Ok(result) - } - - internal fun operatorShiftLeftInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - TODO("<< in array") - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place <<")) // TODO - - val result = mutableListOf() - if(codeGen.isOne(operand)){ - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.LSLM, vmDt, address = constAddress) - else - IRInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol) - , null) - } else { - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) - ,null) - } - return Ok(result) - } - - internal fun operatorXorInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - val result = mutableListOf() - val constIndex = array.index.asConstInteger() - val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) - if(constIndex!=null && constValue!=null) { - if(array.splitWords) { - val valueRegLsb = codeGen.registers.nextFree() - val valueRegMsb = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) - it += IRInstruction(Opcode.XORM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) - it += IRInstruction(Opcode.XORM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) - } - } else { - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) - it += IRInstruction(Opcode.XORM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - } - } - return Ok(result) - } - return Err(NotImplementedError("inplace word array xor")) // TODO? - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place xor")) // TODO - - val result = mutableListOf() - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) - ,null) - return Ok(result) - } - - internal fun operatorModuloInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) { - TODO("% in array") - } - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place %")) // TODO - - val result = mutableListOf() - val resultReg = codeGen.registers.nextFree() - if(operand is PtNumber) { - val number = operand.number.toInt() - if (constAddress != null) { - // @(address) = @(address) %= operand - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, address = constAddress) - it += IRInstruction(Opcode.MOD, vmDt, reg1 = resultReg, immediate = number) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, address = constAddress) - } - } else { - // symbol = symbol %= operand - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, labelSymbol = symbol) - it += IRInstruction(Opcode.MOD, vmDt, reg1 = resultReg, immediate = number) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, labelSymbol = symbol) - } - } - } else { - val tr = translateExpression(operand) - result += tr.chunks - if (constAddress != null) { - // @(address) = @(address) %= operand - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, address = constAddress) - it += IRInstruction(Opcode.MODR, vmDt, reg1 = resultReg, reg2 = tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, address = constAddress) - } - } else { - // symbol = symbol %= operand - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, labelSymbol = symbol) - it += IRInstruction(Opcode.MODR, vmDt, reg1 = resultReg, reg2 = tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, labelSymbol = symbol) - } - } - } - return Ok(result) - } - - internal fun operatorEqualsInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) - return createInplaceArrayComparison(array, operand, "==") - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place compare")) // TODO - - val chunks = if(vmDt==IRDataType.FLOAT) { - createInplaceFloatComparison(constAddress, symbol, operand, Opcode.SEQ) - } else { - createInplaceComparison(constAddress, symbol, vmDt, operand, Opcode.SEQ) - } - return Ok(chunks) - } - - internal fun operatorNotEqualsInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { - if(array!=null) - return createInplaceArrayComparison(array, operand, "!=") - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place compare")) // TODO - - val chunks = if(vmDt==IRDataType.FLOAT) { - createInplaceFloatComparison(constAddress, symbol, operand, Opcode.SNE) - } else { - createInplaceComparison(constAddress, symbol, vmDt, operand, Opcode.SNE) - } - return Ok(chunks) - } - - internal fun operatorGreaterInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result { - if(array!=null) - return createInplaceArrayComparison(array, operand, ">") - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place compare")) // TODO - - val opcode = if(signed) Opcode.SGTS else Opcode.SGT - val chunks = if(vmDt==IRDataType.FLOAT) { - createInplaceFloatComparison(constAddress, symbol, operand, opcode) - } else { - createInplaceComparison(constAddress, symbol, vmDt, operand, opcode) - } - return Ok(chunks) - } - - internal fun operatorLessInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result { - if(array!=null) - return createInplaceArrayComparison(array, operand, "<") - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place compare")) // TODO - - val opcode = if(signed) Opcode.SLTS else Opcode.SLT - val chunks = if(vmDt==IRDataType.FLOAT) { - createInplaceFloatComparison(constAddress, symbol, operand, opcode) - } else { - createInplaceComparison(constAddress, symbol, vmDt, operand, opcode) - } - return Ok(chunks) - } - - internal fun operatorGreaterEqualInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result { - if(array!=null) - return createInplaceArrayComparison(array, operand, ">=") - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place compare")) // TODO - - val opcode = if(signed) Opcode.SGES else Opcode.SGE - val chunks = if(vmDt==IRDataType.FLOAT) { - createInplaceFloatComparison(constAddress, symbol, operand, opcode) - } else { - createInplaceComparison(constAddress, symbol, vmDt, operand, opcode) - } - return Ok(chunks) - } - - internal fun operatorLessEqualInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result { - if(array!=null) - return createInplaceArrayComparison(array, operand, "<=") - if(constAddress==null && memory!=null) - return Err(NotImplementedError("optimized memory in-place compare")) // TODO - - val opcode = if(signed) Opcode.SLES else Opcode.SLE - val chunks = if(vmDt==IRDataType.FLOAT) { - createInplaceFloatComparison(constAddress, symbol, operand, opcode) - } else { - createInplaceComparison(constAddress, symbol, vmDt, operand, opcode) - } - return Ok(chunks) - } - - private fun createInplaceComparison( - constAddress: Int?, - symbol: String?, - vmDt: IRDataType, - operand: PtExpression, - compareAndSetOpcode: Opcode - ): MutableList { - val result = mutableListOf() - val valueReg = codeGen.registers.nextFree() - val cmpResultReg = codeGen.registers.nextFree() - if(operand is PtNumber || operand is PtBool) { - - if(operand is PtNumber && operand.number==0.0 && compareAndSetOpcode in arrayOf(Opcode.SEQ, Opcode.SNE)) { - // ==0 or !=0 optimized case - val compareAndSetOpcodeZero = if(compareAndSetOpcode==Opcode.SEQ) Opcode.SZ else Opcode.SNZ - if (constAddress != null) { - // in-place modify a memory location - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = constAddress) - it += IRInstruction(compareAndSetOpcodeZero, vmDt, reg1 = cmpResultReg, reg2 = valueReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress) - } - } else { - // in-place modify a symbol (variable) - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) - it += IRInstruction(compareAndSetOpcodeZero, vmDt, reg1=cmpResultReg, reg2 = valueReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) - } - } - return result - } - - // compare against number that is not 0 - val numberReg = codeGen.registers.nextFree() - val value = if(operand is PtNumber) operand.number.toInt() else if(operand is PtBool) operand.asInt() else throw AssemblyError("wrong operand type") - if (constAddress != null) { - // in-place modify a memory location - val innervalue = if(operand is PtNumber) operand.number.toInt() else if(operand is PtBool) operand.asInt() else throw AssemblyError("wrong operand type") - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = constAddress) - it += IRInstruction(Opcode.LOAD, vmDt, reg1=numberReg, immediate = innervalue) - it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = cmpResultReg, reg2 = valueReg, reg3 = numberReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress) - } - } else { - // in-place modify a symbol (variable) - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) - it += IRInstruction(Opcode.LOAD, vmDt, reg1=numberReg, immediate = value) - it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = numberReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) - } - } - } else { - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - if (constAddress != null) { - // in-place modify a memory location - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = constAddress) - it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress) - } - } else { - // in-place modify a symbol (variable) - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) - it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) - } - } - } - return result - } - - private fun createInplaceFloatComparison( - constAddress: Int?, - symbol: String?, - operand: PtExpression, - compareAndSetOpcode: Opcode - ): MutableList { - val result = mutableListOf() - val valueReg = codeGen.registers.nextFreeFloat() - val cmpReg = codeGen.registers.nextFree() - val zeroReg = codeGen.registers.nextFree() - if(operand is PtNumber) { - val numberReg = codeGen.registers.nextFreeFloat() - val cmpResultReg = codeGen.registers.nextFree() - if (constAddress != null) { - // in-place modify a memory location - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress) - it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number) - it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = numberReg) - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) - it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) - it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) - it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress) - } - } else { - // in-place modify a symbol (variable) - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) - it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number) - it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = numberReg) - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) - it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) - it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) - it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) - } - } - } else { - val tr = translateExpression(operand) - val cmpResultReg = codeGen.registers.nextFree() - addToResult(result, tr, -1, tr.resultFpReg) - if (constAddress != null) { - // in-place modify a memory location - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress) - it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = tr.resultFpReg) - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) - it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) - it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) - it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress) - } - } else { - // in-place modify a symbol (variable) - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) - it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = tr.resultFpReg) - it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) - it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) - it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) - it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) - } - } - } - return result - } - - private fun createInplaceArrayComparison(array: PtArrayIndexer, value: PtExpression, comparisonOperator: String): Result { - if(array.type==DataType.FLOAT) - return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO? - - val eltSize = codeGen.program.memsizer.memorySize(array.type) - val result = mutableListOf() - if(array.splitWords) - TODO("inplace compare for split word array") - val vmDt = irType(array.type) - val constIndex = array.index.asConstInteger() - val constValue = value.asConstInteger() - val cmpResultReg = codeGen.registers.nextFree() - if(constIndex!=null) { - if(constValue==0) { - // comparison against zero. - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - when(comparisonOperator) { - "==" -> it += IRInstruction(Opcode.SZ, vmDt, reg1=cmpResultReg, reg2=valueReg) - "!=" -> it += IRInstruction(Opcode.SNZ, vmDt, reg1=cmpResultReg, reg2=valueReg) - "<" -> return Err(NotImplementedError("array <0 inplace")) // TODO? - "<=" -> return Err(NotImplementedError("array <=0 inplace")) // TODO? - ">" -> return Err(NotImplementedError("array >0 inplace")) // TODO? - ">=" -> return Err(NotImplementedError("array >=0 inplace")) // TODO? - else -> throw AssemblyError("invalid operator") - } - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) - } - return Ok(result) - } else { - return Err(NotImplementedError("compare against non-zero value")) - } - } else { - if(constValue==0) { - // comparison against zero. - val valueReg = codeGen.registers.nextFree() - val indexTr = translateExpression(array.index) - addToResult(result, indexTr, indexTr.resultReg, -1) - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADX, vmDt, reg1=valueReg, reg2=indexTr.resultReg, labelSymbol = array.variable.name) - when(comparisonOperator) { - "==" -> it += IRInstruction(Opcode.SZ, vmDt, reg1=cmpResultReg, reg2=valueReg) - "!=" -> it += IRInstruction(Opcode.SNZ, vmDt, reg1=cmpResultReg, reg2=valueReg) - "<" -> return Err(NotImplementedError("array <0 inplace")) // TODO? - "<=" -> return Err(NotImplementedError("array <=0 inplace")) // TODO? - ">" -> return Err(NotImplementedError("array >0 inplace")) // TODO? - ">=" -> return Err(NotImplementedError("array >=0 inplace")) // TODO? - else -> throw AssemblyError("invalid operator") - } - it += IRInstruction(Opcode.STOREX, vmDt, reg1=valueReg, reg2=indexTr.resultReg, labelSymbol = array.variable.name) - } - return Ok(result) - } - else - return Err(NotImplementedError("compare against non-zero value")) - } - } - }