IR: integrate inplace assignment ops

This commit is contained in:
Irmen de Jong 2024-01-26 23:14:12 +01:00
parent 39d2194d8f
commit 9553248ed6
4 changed files with 426 additions and 333 deletions

View File

@ -23,114 +23,43 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
if(augAssign.target.children.single() is PtMachineRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
val ident = augAssign.target.identifier
val memory = augAssign.target.memory
val array = augAssign.target.array
val target = augAssign.target
val targetDt = irType(target.type)
val memTarget = target.memory
val constAddress = (memTarget?.address as? PtNumber)?.number?.toInt()
val symbol = target.identifier?.name
val array = target.array
val value = augAssign.value
val signed = target.type in SignedDatatypes
val result: Result<IRCodeChunks, NotImplementedError> = when(augAssign.operator) {
"+=" -> expressionEval.operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value)
"-=" -> expressionEval.operatorMinusInplace(symbol, array, constAddress, memTarget, targetDt, value)
"*=" -> expressionEval.operatorMultiplyInplace(symbol, array, constAddress, memTarget, targetDt, value)
"/=" -> expressionEval.operatorDivideInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
"|=" -> expressionEval.operatorOrInplace(symbol, array, constAddress, memTarget, targetDt, value)
"or=" -> expressionEval.operatorLogicalOrInplace(symbol, array, constAddress, memTarget, targetDt, value)
"&=" -> expressionEval.operatorAndInplace(symbol, array, constAddress, memTarget, targetDt, value)
"and=" -> expressionEval.operatorLogicalAndInplace(symbol, array, constAddress, memTarget, targetDt, value)
"^=", "xor=" -> expressionEval.operatorXorInplace(symbol, array, constAddress, memTarget, targetDt, value)
"<<=" -> expressionEval.operatorShiftLeftInplace(symbol, array, constAddress, memTarget, targetDt, value)
">>=" -> expressionEval.operatorShiftRightInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
"%=" -> expressionEval.operatorModuloInplace(symbol, array, constAddress, memTarget, targetDt, value)
"==" -> expressionEval.operatorEqualsInplace(symbol, array, constAddress, memTarget, targetDt, value)
"!=" -> expressionEval.operatorNotEqualsInplace(symbol, array, constAddress, memTarget, targetDt, value)
"<" -> expressionEval.operatorLessInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
">" -> expressionEval.operatorGreaterInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
"<=" -> expressionEval.operatorLessEqualInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
">=" -> expressionEval.operatorGreaterEqualInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
in PrefixOperators -> inplacePrefix(augAssign.operator, symbol, array, constAddress, memTarget, targetDt)
// TODO don't fragment the implementation over multiple subroutines
val chunks = if(ident!=null) {
assignVarAugmented(ident.name, augAssign)
} else if(memory != null) {
if(memory.address is PtNumber)
assignMemoryAugmented((memory.address as PtNumber).number.toInt(), augAssign)
else
fallbackAssign(augAssign)
} else if(array!=null) {
assignArrayAugmented(array, augAssign)
} else {
fallbackAssign(augAssign)
else -> throw AssemblyError("invalid augmented assign operator ${augAssign.operator}")
}
val chunks = result.getOrElse { fallbackAssign(augAssign) }
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(augAssign.position)
return chunks
}
private fun assignMemoryAugmented(address: Int, assignment: PtAugmentedAssign): IRCodeChunks {
val value = assignment.value
val targetDt = irType(assignment.target.type)
val signed = assignment.target.type in SignedDatatypes
return when(assignment.operator) {
"+=" -> expressionEval.operatorPlusInplace(address, null, targetDt, value)
"-=" -> expressionEval.operatorMinusInplace(address, null, targetDt, value)
"*=" -> expressionEval.operatorMultiplyInplace(address, null, targetDt, value)
"/=" -> expressionEval.operatorDivideInplace(address, null, targetDt, signed, value)
"|=" -> expressionEval.operatorOrInplace(address, null, targetDt, value)
"&=" -> expressionEval.operatorAndInplace(address, null, targetDt, value)
"^=" -> expressionEval.operatorXorInplace(address, null, targetDt, value)
"<<=" -> expressionEval.operatorShiftLeftInplace(address, null, targetDt, value)
">>=" -> expressionEval.operatorShiftRightInplace(address, null, targetDt, signed, value)
"%=" -> expressionEval.operatorModuloInplace(address, null, targetDt, value)
"==" -> expressionEval.operatorEqualsNotEqualsInplace(address, null, targetDt, value)
"!=" -> expressionEval.operatorNotEqualsInplace(address, null, targetDt, value)
"<" -> expressionEval.operatorLessInplace(address, null, targetDt, signed, value)
">" -> expressionEval.operatorGreaterInplace(address, null, targetDt, signed, value)
"<=" -> expressionEval.operatorLessEqualInplace(address, null, targetDt, signed, value)
">=" -> expressionEval.operatorGreaterEqualInplace(address, null, targetDt, signed, value)
in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, address, null)
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
}
}
private fun assignVarAugmented(symbol: String, assignment: PtAugmentedAssign): IRCodeChunks {
val value = assignment.value
val signed = assignment.target.type in SignedDatatypes
val targetDt = irType(assignment.target.type)
return when(assignment.operator) {
"+=" -> expressionEval.operatorPlusInplace(null, symbol, targetDt, value)
"-=" -> expressionEval.operatorMinusInplace(null, symbol, targetDt, value)
"*=" -> expressionEval.operatorMultiplyInplace(null, symbol, targetDt, value)
"/=" -> expressionEval.operatorDivideInplace(null, symbol, targetDt, signed, value)
"|=" -> expressionEval.operatorOrInplace(null, symbol, targetDt, value)
"or=" -> expressionEval.operatorLogicalOrInplace(null, symbol, targetDt, value)
"&=" -> expressionEval.operatorAndInplace(null, symbol, targetDt, value)
"and=" -> expressionEval.operatorLogicalAndInplace(null, symbol, targetDt, value)
"^=", "xor=" -> expressionEval.operatorXorInplace(null, symbol, targetDt, value)
"<<=" -> expressionEval.operatorShiftLeftInplace(null, symbol, targetDt, value)
">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, targetDt, signed, value)
"%=" -> expressionEval.operatorModuloInplace(null, symbol, targetDt, value)
"==" -> expressionEval.operatorEqualsNotEqualsInplace(null, symbol, targetDt, value)
"!=" -> expressionEval.operatorNotEqualsInplace(null, symbol, targetDt, value)
"<" -> expressionEval.operatorLessInplace(null, symbol, targetDt, signed, value)
">" -> expressionEval.operatorGreaterInplace(null, symbol, targetDt, signed, value)
"<=" -> expressionEval.operatorLessEqualInplace(null, symbol, targetDt, signed, value)
">=" -> expressionEval.operatorGreaterEqualInplace(null, symbol, targetDt, signed, value)
in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, null, symbol)
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
}
}
private fun assignArrayAugmented(array: PtArrayIndexer, assignment: PtAugmentedAssign): IRCodeChunks {
val eltSize = codeGen.program.memsizer.memorySize(array.type)
val value = assignment.value
val signed = assignment.target.type in SignedDatatypes
val result = when(assignment.operator) {
// TODO implement all of these:
// "+=" -> expressionEval.operatorPlusInplace(array, eltSize, value)
// "-=" -> expressionEval.operatorMinusInplace(array, eltSize, value)
// "*=" -> expressionEval.operatorMultiplyInplace(array, eltSize, value)
// "/=" -> expressionEval.operatorDivideInplace(array, eltSize, signed, value)
// "|=" -> expressionEval.operatorOrInplace(array, eltSize, value)
// "&=" -> expressionEval.operatorAndInplace(array, eltSize, value)
// "^=" -> expressionEval.operatorXorInplace(array, eltSize, value)
// "<<=" -> expressionEval.operatorShiftLeftInplace(array, eltSize, value)
// ">>=" -> expressionEval.operatorShiftRightInplace(array, eltSize, signed, value)
// "%=" -> expressionEval.operatorModuloInplace(array, eltSize, value)
"==" -> expressionEval.operatorEqualsInplace(array, eltSize, value)
"!=" -> expressionEval.operatorNotEqualsInplace(array, eltSize, value)
"<" -> expressionEval.operatorLessInplace(array, eltSize, signed, value)
">" -> expressionEval.operatorGreaterInplace(array, eltSize, signed, value)
"<=" -> expressionEval.operatorLessEqualInplace(array, eltSize, signed, value)
">=" -> expressionEval.operatorGreaterEqualInplace(array, eltSize, signed, value)
in PrefixOperators -> inplacePrefix(assignment.operator, array, eltSize)
// else -> Err(NotImplementedError("invalid augmented assign operator ${assignment.operator}"))
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
}
return result.getOrElse { fallbackAssign(assignment) }
}
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
val value: PtExpression
if(origAssign.operator in PrefixOperators) {
@ -155,7 +84,47 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
return translateRegularAssign(normalAssign)
}
private fun inplacePrefix(operator: String, array: PtArrayIndexer, eltSize: Int): Result<IRCodeChunks, NotImplementedError> {
private fun inplacePrefix(operator: String, symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType): Result<IRCodeChunks, NotImplementedError> {
if(operator=="+")
return Ok(emptyList())
if(array!=null)
return Ok(inplacePrefixArray(operator, array))
val result = mutableListOf<IRCodeChunkBase>()
if(constAddress==null && memory!=null) {
val register = codeGen.registers.nextFree()
val tr = expressionEval.translateExpression(memory.address)
addToResult(result, tr, tr.resultReg, -1)
when(operator) {
"-" -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADI, vmDt, reg1=register, reg2=tr.resultReg)
it += IRInstruction(Opcode.NEG, vmDt, reg1=register)
it += IRInstruction(Opcode.STOREI, vmDt, reg1=register, reg2=tr.resultReg)
}
}
"~" -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADI, vmDt, reg1=register, reg2=tr.resultReg)
it += IRInstruction(Opcode.INV, vmDt, reg1=register)
it += IRInstruction(Opcode.STOREI, vmDt, reg1=register, reg2=tr.resultReg)
}
}
}
} else {
when (operator) {
"-" -> addInstr(result, IRInstruction(Opcode.NEGM, vmDt, address = constAddress, labelSymbol = symbol), null)
"~" -> addInstr(result, IRInstruction(Opcode.INVM, vmDt, address = constAddress, labelSymbol = symbol), null)
// TODO: in boolean branch, how is 'not' handled here?
else -> throw AssemblyError("weird prefix operator")
}
}
return Ok(result)
}
private fun inplacePrefixArray(operator: String, array: PtArrayIndexer): IRCodeChunks {
val eltSize = codeGen.program.memsizer.memorySize(array.type)
val result = mutableListOf<IRCodeChunkBase>()
val vmDt = irType(array.type)
val constIndex = array.index.asConstInteger()
@ -217,7 +186,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
}
else -> throw AssemblyError("weird prefix operator")
}
return Ok(result)
return result
}
// normal array.
@ -269,19 +238,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
}
else -> throw AssemblyError("weird prefix operator")
}
return Ok(result)
}
private fun inplacePrefix(operator: String, vmDt: IRDataType, address: Int?, symbol: String?): IRCodeChunks {
val code= IRCodeChunk(null, null)
when(operator) {
"+" -> { }
"-" -> code += IRInstruction(Opcode.NEGM, vmDt, address = address, labelSymbol = symbol)
"~" -> code += IRInstruction(Opcode.INVM, vmDt, address = address, labelSymbol = symbol)
// TODO: in boolean branch, how is 'not' handled here?
else -> throw AssemblyError("weird prefix operator")
}
return listOf(code)
return result
}
private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunks {

View File

@ -999,18 +999,30 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("&")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place &")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorLogicalAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorLogicalAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("and")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place and")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
val tr = translateExpression(operand)
if(!operand.isSimple()) {
@ -1018,41 +1030,53 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val inplaceReg = codeGen.registers.nextFree()
val shortcutLabel = codeGen.createLabelName()
result += IRCodeChunk(null, null).also {
it += if(knownAddress!=null)
IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, address = knownAddress)
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(knownAddress!=null)
IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, address = knownAddress)
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(knownAddress!=null)
IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("|")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place |")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorLogicalOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorLogicalOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("or")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place or")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
val tr = translateExpression(operand)
if(!operand.isSimple()) {
@ -1060,48 +1084,54 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val inplaceReg = codeGen.registers.nextFree()
val shortcutLabel = codeGen.createLabelName()
result += IRCodeChunk(null, null).also {
it += if(knownAddress!=null)
IRInstruction(Opcode.LOADM, vmDt, reg1=inplaceReg, address = knownAddress)
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(knownAddress!=null)
IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, address = knownAddress)
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(knownAddress!=null)
IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks {
internal fun operatorDivideInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("/")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place /")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
val constFactorRight = operand as? PtNumber
if(vmDt==IRDataType.FLOAT) {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
val factor = constFactorRight.number
result += codeGen.divideByConstFloatInplace(knownAddress, symbol, factor)
result += codeGen.divideByConstFloatInplace(constAddress, symbol, factor)
} else {
val tr = translateExpression(operand)
addToResult(result, tr, -1, tr.resultFpReg)
val ins = if(signed) {
if(knownAddress!=null)
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, address = knownAddress)
if(constAddress!=null)
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress)
else
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol)
}
else {
if(knownAddress!=null)
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, address = knownAddress)
if(constAddress!=null)
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress)
else
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol)
}
@ -1110,40 +1140,46 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
val factor = constFactorRight.number.toInt()
result += codeGen.divideByConstInplace(vmDt, knownAddress, symbol, factor, signed)
result += codeGen.divideByConstInplace(vmDt, constAddress, symbol, factor, signed)
} else {
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
val ins = if(signed) {
if(knownAddress!=null)
IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, address = knownAddress)
if(constAddress!=null)
IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, address = constAddress)
else
IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol)
}
else {
if(knownAddress!=null)
IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorMultiplyInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("*")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place *")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
val constFactorRight = operand as? PtNumber
if(vmDt==IRDataType.FLOAT) {
if(constFactorRight!=null) {
val factor = constFactorRight.number
result += codeGen.multiplyByConstFloatInplace(knownAddress, symbol, factor)
result += codeGen.multiplyByConstFloatInplace(constAddress, symbol, factor)
} else {
val tr = translateExpression(operand)
addToResult(result, tr, -1, tr.resultFpReg)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, address = knownAddress)
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)
@ -1151,26 +1187,32 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
val factor = constFactorRight.number.toInt()
result += codeGen.multiplyByConstInplace(vmDt, knownAddress, symbol, factor)
result += codeGen.multiplyByConstInplace(vmDt, constAddress, symbol, factor)
} else {
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorMinusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("-")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place -")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
if(vmDt==IRDataType.FLOAT) {
if((operand as? PtNumber)?.number==1.0) {
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.DECM, vmDt, address = knownAddress)
addInstr(result, if(constAddress!=null)
IRInstruction(Opcode.DECM, vmDt, address = constAddress)
else
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
, null)
@ -1178,16 +1220,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
else {
val tr = translateExpression(operand)
addToResult(result, tr, -1, tr.resultFpReg)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, address = knownAddress)
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(knownAddress!=null)
IRInstruction(Opcode.DECM, vmDt, address = knownAddress)
addInstr(result, if(constAddress!=null)
IRInstruction(Opcode.DECM, vmDt, address = constAddress)
else
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
, null)
@ -1195,22 +1237,28 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
else {
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorPlusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("+")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place +")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
if(vmDt==IRDataType.FLOAT) {
if((operand as? PtNumber)?.number==1.0) {
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.INCM, vmDt, address = knownAddress)
addInstr(result, if(constAddress!=null)
IRInstruction(Opcode.INCM, vmDt, address = constAddress)
else
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
, null)
@ -1218,16 +1266,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
else {
val tr = translateExpression(operand)
addToResult(result, tr, -1, tr.resultFpReg)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, address = knownAddress)
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(knownAddress!=null)
IRInstruction(Opcode.INCM, vmDt, address = knownAddress)
addInstr(result, if(constAddress!=null)
IRInstruction(Opcode.INCM, vmDt, address = constAddress)
else
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
, null)
@ -1235,22 +1283,28 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
else {
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks {
internal fun operatorShiftRightInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO(">>")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place >>")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
if(codeGen.isOne(operand)) {
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
val ins = if(knownAddress!=null)
IRInstruction(opc, vmDt, address = knownAddress)
val ins = if(constAddress!=null)
IRInstruction(opc, vmDt, address = constAddress)
else
IRInstruction(opc, vmDt, labelSymbol = symbol)
addInstr(result, ins, null)
@ -1258,58 +1312,76 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
val ins = if(knownAddress!=null)
IRInstruction(opc, vmDt, reg1 = tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorShiftLeftInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("<<")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place <<")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
if(codeGen.isOne(operand)){
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.LSLM, vmDt, address = knownAddress)
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(knownAddress!=null)
IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorXorInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("xor")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place xor")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, if(knownAddress!=null)
IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, address = knownAddress)
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
return Ok(result)
}
fun operatorModuloInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
internal fun operatorModuloInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array!=null) {
TODO("%")
}
if(constAddress==null && memory!=null)
return Err(NotImplementedError("optimized memory in-place %")) // TODO
val result = mutableListOf<IRCodeChunkBase>()
val resultReg = codeGen.registers.nextFree()
if(operand is PtNumber) {
val number = operand.number.toInt()
if (knownAddress != null) {
if (constAddress != null) {
// @(address) = @(address) %= operand
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, address = knownAddress)
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 = knownAddress)
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, address = constAddress)
}
} else {
// symbol = symbol %= operand
@ -1322,12 +1394,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} else {
val tr = translateExpression(operand)
result += tr.chunks
if (knownAddress != null) {
if (constAddress != null) {
// @(address) = @(address) %= operand
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, address = knownAddress)
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 = knownAddress)
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, address = constAddress)
}
} else {
// symbol = symbol %= operand
@ -1338,64 +1410,99 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
}
}
return result
return Ok(result)
}
fun operatorEqualsNotEqualsInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
return if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(knownAddress, symbol, operand, Opcode.SEQ)
internal fun operatorEqualsInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
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(knownAddress, symbol, vmDt, operand, Opcode.SEQ)
createInplaceComparison(constAddress, symbol, vmDt, operand, Opcode.SEQ)
}
return Ok(chunks)
}
fun operatorNotEqualsInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks {
return if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(knownAddress, symbol, operand, Opcode.SNE)
internal fun operatorNotEqualsInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result<IRCodeChunks, NotImplementedError> {
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(knownAddress, symbol, vmDt, operand, Opcode.SNE)
createInplaceComparison(constAddress, symbol, vmDt, operand, Opcode.SNE)
}
return Ok(chunks)
}
fun operatorGreaterInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks {
internal fun operatorGreaterInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result<IRCodeChunks, NotImplementedError> {
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
return if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(knownAddress, symbol, operand, opcode)
val chunks = if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(constAddress, symbol, operand, opcode)
} else {
createInplaceComparison(knownAddress, symbol, vmDt, operand, opcode)
createInplaceComparison(constAddress, symbol, vmDt, operand, opcode)
}
return Ok(chunks)
}
fun operatorLessInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks {
internal fun operatorLessInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result<IRCodeChunks, NotImplementedError> {
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
return if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(knownAddress, symbol, operand, opcode)
val chunks = if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(constAddress, symbol, operand, opcode)
} else {
createInplaceComparison(knownAddress, symbol, vmDt, operand, opcode)
createInplaceComparison(constAddress, symbol, vmDt, operand, opcode)
}
return Ok(chunks)
}
fun operatorGreaterEqualInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks {
internal fun operatorGreaterEqualInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result<IRCodeChunks, NotImplementedError> {
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
return if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(knownAddress, symbol, operand, opcode)
val chunks = if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(constAddress, symbol, operand, opcode)
} else {
createInplaceComparison(knownAddress, symbol, vmDt, operand, opcode)
createInplaceComparison(constAddress, symbol, vmDt, operand, opcode)
}
return Ok(chunks)
}
fun operatorLessEqualInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks {
internal fun operatorLessEqualInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result<IRCodeChunks, NotImplementedError> {
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
return if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(knownAddress, symbol, operand, opcode)
val chunks = if(vmDt==IRDataType.FLOAT) {
createInplaceFloatComparison(constAddress, symbol, operand, opcode)
} else {
createInplaceComparison(knownAddress, symbol, vmDt, operand, opcode)
createInplaceComparison(constAddress, symbol, vmDt, operand, opcode)
}
return Ok(chunks)
}
private fun createInplaceComparison(
knownAddress: Int?,
constAddress: Int?,
symbol: String?,
vmDt: IRDataType,
operand: PtExpression,
@ -1409,12 +1516,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
if(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 (knownAddress != null) {
if (constAddress != null) {
// in-place modify a memory location
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = knownAddress)
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 = knownAddress)
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress)
}
} else {
// in-place modify a symbol (variable)
@ -1429,13 +1536,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
// compare against number that is not 0
val numberReg = codeGen.registers.nextFree()
if (knownAddress != null) {
if (constAddress != null) {
// in-place modify a memory location
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = knownAddress)
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = constAddress)
it += IRInstruction(Opcode.LOAD, vmDt, reg1=numberReg, immediate = operand.number.toInt())
it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = cmpResultReg, reg2 = valueReg, reg3 = numberReg)
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = knownAddress)
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress)
}
} else {
// in-place modify a symbol (variable)
@ -1449,12 +1556,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} else {
val tr = translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1)
if (knownAddress != null) {
if (constAddress != null) {
// in-place modify a memory location
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = knownAddress)
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 = knownAddress)
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = constAddress)
}
} else {
// in-place modify a symbol (variable)
@ -1469,7 +1576,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
private fun createInplaceFloatComparison(
knownAddress: Int?,
constAddress: Int?,
symbol: String?,
operand: PtExpression,
compareAndSetOpcode: Opcode
@ -1481,16 +1588,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
if(operand is PtNumber) {
val numberReg = codeGen.registers.nextFreeFloat()
val cmpResultReg = codeGen.registers.nextFree()
if (knownAddress != null) {
if (constAddress != null) {
// in-place modify a memory location
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, address = knownAddress)
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 = knownAddress)
it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress)
}
} else {
// in-place modify a symbol (variable)
@ -1508,15 +1615,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val tr = translateExpression(operand)
val cmpResultReg = codeGen.registers.nextFree()
addToResult(result, tr, -1, tr.resultFpReg)
if (knownAddress != null) {
if (constAddress != null) {
// in-place modify a memory location
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, address = knownAddress)
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 = knownAddress)
it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, address = constAddress)
}
} else {
// in-place modify a symbol (variable)
@ -1533,82 +1640,65 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
return result
}
fun operatorEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
private fun createInplaceArrayComparison(array: PtArrayIndexer, value: PtExpression, comparisonOperator: String): Result<IRCodeChunks, NotImplementedError> {
if(array.type==DataType.FLOAT)
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
else
return createCompareArrayInplace(array, eltSize, value, Opcode.SZ)
}
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO?
fun operatorNotEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array.type==DataType.FLOAT)
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
else
return createCompareArrayInplace(array, eltSize, value, Opcode.SNZ)
}
fun operatorLessInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array.type==DataType.FLOAT)
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
else
TODO("<")
//return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ)
}
fun operatorLessEqualInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array.type==DataType.FLOAT)
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
else
TODO("<=")
//return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ)
}
fun operatorGreaterInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array.type==DataType.FLOAT)
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
else
TODO(">")
//return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ)
}
fun operatorGreaterEqualInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result<IRCodeChunks, NotImplementedError> {
if(array.type==DataType.FLOAT)
return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO
else
TODO(">=")
//return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ)
}
private fun createCompareArrayInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression, compareAndSetOpcode: Opcode): Result<IRCodeChunks, NotImplementedError> {
require(array.type!=DataType.FLOAT)
val eltSize = codeGen.program.memsizer.memorySize(array.type)
val result = mutableListOf<IRCodeChunkBase>()
if(array.splitWords)
TODO("inplace == for split word array")
TODO("inplace compare for split word array")
if(array.usesPointerVariable)
TODO("inplace == for pointer variable")
TODO("inplace compare for pointer variable")
val vmDt = irType(array.type)
val constIndex = array.index.asConstInteger()
val constValue = value.asConstInteger()
val cmpResultReg = codeGen.registers.nextFree()
if(constIndex!=null) {
if(constValue!=null) {
if(constValue==0) {
// comparison against zero.
val valueReg = codeGen.registers.nextFree()
if(constValue==0) {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2=valueReg)
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
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")
}
} else {
return Err(NotImplementedError("compare against non-zero value"))
it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
}
return Ok(result)
} else {
TODO("non const value")
return Err(NotImplementedError("compare against non-zero value"))
}
} else {
TODO("non const index")
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"))
}
return Ok(result)
}
}

View File

@ -1,9 +1,15 @@
TODO
====
IR ExpressionGen: implement all in-place operators TODOs. Starting with operatorPlusInplace
maze: if cell & UP!=0 and @(celladdr(cx,cy-1)) & (WALKED|BACKTRACKED) ==0
^^ adding this !=0 caused a weird beq + / lda #1 / + to appear in front of the shortcircuit beq...
(after merge in boolean): move all "OperatorXinplace" from expressionGen to AssignmentGen, see if we can get rid of the Result return type.
...
@ -83,7 +89,6 @@ Other language/syntax features to think about
---------------------------------------------
- support for assigning multiple return values from romsub/asmsub to multiple variables.
- remove ++/-- (just use Pythonesque x+=1) OR make ++/-- into a postfix expression (but then we need a prefix variant of them too?) maybe via a new builtin function like postincr__w() etc?
- add (rom/ram)bank support to romsub. A call will then automatically switch banks, use callfar and something else when in banked ram.
challenges: how to not make this too X16 specific? How does the compiler know what bank to switch (ram/rom)?
How to make it performant when we want to (i.e. NOT have it use callfar/auto bank switching) ?

View File

@ -5,38 +5,79 @@
main {
sub start() {
word[3] @split @shared array = [1111,$10ff,3333]
txt.print_w(array[1])
txt.nl()
txt.print_w(-array[1])
txt.nl()
array[1] = -array[1]
txt.print_w(array[1])
txt.nl()
txt.nl()
ubyte @shared idx = 1
txt.print_w(array[idx])
txt.nl()
txt.print_w(-array[idx])
txt.nl()
array[idx] = -array[idx]
txt.print_w(array[idx])
txt.nl()
; ubyte @shared xx
; uword[3] ubarr
; bool[3] barr
; float[3] flarr
; bool @shared bb
; uword @shared addr = 2000
; @(2000) = 199
; txt.print_ub(@(2000))
; txt.nl()
; @(addr) = ~@(addr)
; txt.print_ub(@(2000))
; txt.nl()
;
; word[3] @split @shared array = [1111,$10ff,3333]
;
; txt.print_w(array[1])
; txt.nl()
; txt.print_w(-array[1])
; txt.nl()
; array[1] = -array[1]
; txt.print_w(array[1])
; txt.nl()
; txt.nl()
;
; ubyte @shared idx = 1
; txt.print_w(array[idx])
; txt.nl()
; txt.print_w(-array[idx])
; txt.nl()
; array[idx] = -array[idx]
; txt.print_w(array[idx])
; txt.nl()
;
ubyte @shared xx
ubyte[3] ubarr
byte[3] sbarr
bool[3] barr
float[3] flarr
bool @shared bb
; sbarr[1] = sbarr[1] == 0
; sbarr[1] = sbarr[1] != 0
; sbarr[1] = sbarr[1] < 0
; sbarr[1] = sbarr[1] <= 0
; sbarr[1] = sbarr[1] > 0
; sbarr[1] = sbarr[1] >= 0
;
; xx = 1
;
; sbarr[xx] = sbarr[xx] == 0
; sbarr[xx] = sbarr[xx] != 0
; sbarr[xx] = sbarr[xx] < 0
; sbarr[xx] = sbarr[xx] <= 0
; sbarr[xx] = sbarr[xx] > 0
; sbarr[xx] = sbarr[xx] >= 0
sbarr[1] = sbarr[1] == 2
sbarr[1] = sbarr[1] != 2
sbarr[1] = sbarr[1] < 2
sbarr[1] = sbarr[1] <= 2
sbarr[1] = sbarr[1] > 2
sbarr[1] = sbarr[1] >= 2
xx = 1
sbarr[xx] = sbarr[xx] == 2
sbarr[xx] = sbarr[xx] != 2
sbarr[xx] = sbarr[xx] < 2
sbarr[xx] = sbarr[xx] <= 2
sbarr[xx] = sbarr[xx] > 2
sbarr[xx] = sbarr[xx] >= 2
; ubarr[1] = ubarr[1] == 2
; ubarr[1] = ubarr[1] < 2
; ubarr[1] = ubarr[1] <= 2
; ubarr[1] = ubarr[1] > 3
; ubarr[1] = ubarr[1] >= 3
;
; barr[1] = barr[0] and barr[2]
; barr[1] = barr[0] or barr[2]
; barr[1] = barr[0] xor barr[2]