This commit is contained in:
Irmen de Jong 2023-03-26 15:06:04 +02:00
parent 629ed74d09
commit 5cbf859458

View File

@ -31,84 +31,95 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
} }
private fun augmentedAssignExpr(assign: AsmAugmentedAssignment) { private fun augmentedAssignExpr(assign: AsmAugmentedAssignment) {
val srcValue = assign.source.toAstExpression(assign.target.scope as PtNamedNode)
when (assign.operator) { when (assign.operator) {
"+=" -> inplaceModification(assign.target, "+", srcValue) "+=" -> inplaceModification(assign.target, "+", assign.source)
"-=" -> inplaceModification(assign.target, "-", srcValue) "-=" -> inplaceModification(assign.target, "-", assign.source)
"*=" -> inplaceModification(assign.target, "*", srcValue) "*=" -> inplaceModification(assign.target, "*", assign.source)
"/=" -> inplaceModification(assign.target, "/", srcValue) "/=" -> inplaceModification(assign.target, "/", assign.source)
"|=" -> inplaceModification(assign.target, "|", srcValue) "|=" -> inplaceModification(assign.target, "|", assign.source)
"&=" -> inplaceModification(assign.target, "&", srcValue) "&=" -> inplaceModification(assign.target, "&", assign.source)
"^=" -> inplaceModification(assign.target, "^", srcValue) "^=" -> inplaceModification(assign.target, "^", assign.source)
"<<=" -> inplaceModification(assign.target, "<<", srcValue) "<<=" -> inplaceModification(assign.target, "<<", assign.source)
">>=" -> inplaceModification(assign.target, ">>", srcValue) ">>=" -> inplaceModification(assign.target, ">>", assign.source)
"%=" -> inplaceModification(assign.target, "%", srcValue) "%=" -> inplaceModification(assign.target, "%", assign.source)
"==" -> inplaceModification(assign.target, "==", srcValue) "==" -> inplaceModification(assign.target, "==", assign.source)
"!=" -> inplaceModification(assign.target, "!=", srcValue) "!=" -> inplaceModification(assign.target, "!=", assign.source)
"<" -> inplaceModification(assign.target, "<", srcValue) "<" -> inplaceModification(assign.target, "<", assign.source)
">" -> inplaceModification(assign.target, ">", srcValue) ">" -> inplaceModification(assign.target, ">", assign.source)
"<=" -> inplaceModification(assign.target, "<=", srcValue) "<=" -> inplaceModification(assign.target, "<=", assign.source)
">=" -> inplaceModification(assign.target, ">=", srcValue) ">=" -> inplaceModification(assign.target, ">=", assign.source)
else -> throw AssemblyError("invalid augmented assign operator ${assign.operator}") else -> throw AssemblyError("invalid augmented assign operator ${assign.operator}")
} }
} }
private fun inplaceModification(target: AsmAssignTarget, operator: String, origValue: PtExpression) { private fun inplaceModification(target: AsmAssignTarget, operator: String, value: AsmAssignSource) {
// the asm-gen code can deal with situations where you want to assign a byte into a word. // the asm-gen code can deal with situations where you want to assign a byte into a word.
// it will create the most optimized code to do this (so it type-extends for us). // it will create the most optimized code to do this (so it type-extends for us).
// But we can't deal with writing a word into a byte - explicit typeconversion is required // But we can't deal with writing a word into a byte - explicit typeconversion should be done
val value = if(program.memsizer.memorySize(origValue.type) > program.memsizer.memorySize(target.datatype)) { if(program.memsizer.memorySize(value.datatype) > program.memsizer.memorySize(target.datatype)) {
val typecast = PtTypeCast(target.datatype, origValue.position) TODO("missing type cast: value type > target type ${target.position}")
typecast.add(origValue)
require(typecast.type!=origValue.type)
typecast
}
else {
origValue
} }
val valueLv = (value as? PtNumber)?.number fun regName(v: AsmAssignSource) = "cx16.${v.register!!.name.lowercase()}"
val ident = value as? PtIdentifier
val memread = value as? PtMemoryByte
when (target.kind) { when (target.kind) {
TargetStorageKind.VARIABLE -> { TargetStorageKind.VARIABLE -> {
when (target.datatype) { when (target.datatype) {
in ByteDatatypes -> { in ByteDatatypes -> {
when { when(value.kind) {
valueLv != null -> inplaceModification_byte_litval_to_variable(target.asmVarname, target.datatype, operator, valueLv.toInt()) SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable(target.asmVarname, target.datatype, operator, value.number!!.number.toInt())
ident != null -> inplaceModification_byte_variable_to_variable(target.asmVarname, target.datatype, operator, ident) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable(target.asmVarname, target.datatype, operator, value.asmVarname)
memread != null -> inplaceModification_byte_memread_to_variable(target.asmVarname, target.datatype, operator, memread) SourceStorageKind.REGISTER -> inplaceModification_byte_variable_to_variable(target.asmVarname, target.datatype, operator, regName(value))
value is PtTypeCast -> { SourceStorageKind.MEMORY -> inplaceModification_byte_memread_to_variable(target.asmVarname, target.datatype, operator, value.memory!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return SourceStorageKind.ARRAY -> inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value.array!!)
inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value) SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value.expression)
} else {
inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value.expression!!)
}
} }
else -> inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
} }
in WordDatatypes -> { in WordDatatypes -> {
when { when(value.kind) {
valueLv != null -> inplaceModification_word_litval_to_variable(target.asmVarname, target.datatype, operator, valueLv.toInt()) SourceStorageKind.LITERALNUMBER -> inplaceModification_word_litval_to_variable(target.asmVarname, target.datatype, operator, value.number!!.number.toInt())
ident != null -> inplaceModification_word_variable_to_variable(target.asmVarname, target.datatype, operator, ident) SourceStorageKind.VARIABLE -> inplaceModification_word_variable_to_variable(target.asmVarname, target.datatype, operator, value.asmVarname, value.datatype)
memread != null -> inplaceModification_word_memread_to_variable(target.asmVarname, target.datatype, operator, memread) SourceStorageKind.REGISTER -> inplaceModification_word_variable_to_variable(target.asmVarname, target.datatype, operator, regName(value), value.datatype)
value is PtTypeCast -> { SourceStorageKind.MEMORY -> inplaceModification_word_memread_to_variable(target.asmVarname, target.datatype, operator, value.memory!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) SourceStorageKind.ARRAY -> inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value.array!!)
return SourceStorageKind.EXPRESSION -> {
inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value) if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
return
inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value.expression)
}
else {
inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value.expression!!)
}
} }
else -> inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
} }
DataType.FLOAT -> { DataType.FLOAT -> {
when { when(value.kind) {
valueLv != null -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, valueLv.toDouble(), target.scope!!) SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, value.number!!.number, target.scope!!)
ident != null -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, ident, target.scope!!) SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, value.asmVarname, target.scope!!)
value is PtTypeCast -> { SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, regName(value), target.scope!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return SourceStorageKind.MEMORY -> TODO("memread into float")
inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope!!) SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value.array!!, target.scope!!)
SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
inplaceModification_float_value_to_variable(target.asmVarname, operator, value.expression, target.scope!!)
} else {
inplaceModification_float_value_to_variable(target.asmVarname, operator, value.expression!!, target.scope!!)
}
} }
else -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope!!) else -> throw AssemblyError("weird source type ${value.kind}")
} }
} }
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
@ -119,43 +130,61 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
when (memory.address) { when (memory.address) {
is PtNumber -> { is PtNumber -> {
val addr = (memory.address as PtNumber).number.toInt() val addr = (memory.address as PtNumber).number.toInt()
// re-use code to assign a variable, instead this time, use a direct memory address when(value.kind) {
when { SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable(addr.toHex(), DataType.UBYTE, operator, value.number!!.number.toInt())
valueLv != null -> inplaceModification_byte_litval_to_variable(addr.toHex(), DataType.UBYTE, operator, valueLv.toInt()) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable(addr.toHex(), DataType.UBYTE, operator, value.asmVarname)
ident != null -> inplaceModification_byte_variable_to_variable(addr.toHex(), DataType.UBYTE, operator, ident) SourceStorageKind.REGISTER -> inplaceModification_byte_variable_to_variable(addr.toHex(), DataType.UBYTE, operator, regName(value))
memread != null -> inplaceModification_byte_memread_to_variable(addr.toHex(), DataType.UBYTE, operator, value) SourceStorageKind.MEMORY -> inplaceModification_byte_memread_to_variable(addr.toHex(), DataType.UBYTE, operator, value.memory!!)
value is PtTypeCast -> { SourceStorageKind.ARRAY -> inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value.array!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return SourceStorageKind.EXPRESSION -> {
inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value) if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value.expression)
} else {
inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value.expression!!)
}
} }
else -> inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
} }
is PtIdentifier -> { is PtIdentifier -> {
val pointer = memory.address as PtIdentifier val pointer = memory.address as PtIdentifier
when { when(value.kind) {
valueLv != null -> inplaceModification_byte_litval_to_pointer(pointer, operator, valueLv.toInt()) SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_pointer(pointer, operator, value.number!!.number.toInt())
ident != null -> inplaceModification_byte_variable_to_pointer(pointer, operator, ident) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_pointer(pointer, operator, value.asmVarname)
value is PtTypeCast -> { SourceStorageKind.REGISTER -> inplaceModification_byte_variable_to_pointer(pointer, operator, regName(value))
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return SourceStorageKind.MEMORY -> TODO("memread into pointer")
inplaceModification_byte_value_to_pointer(pointer, operator, value) SourceStorageKind.ARRAY -> inplaceModification_byte_value_to_pointer(pointer, operator, value.array!!)
SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
inplaceModification_byte_value_to_pointer(pointer, operator, value.expression)
} else {
inplaceModification_byte_value_to_pointer(pointer, operator, value.expression!!)
}
} }
else -> inplaceModification_byte_value_to_pointer(pointer, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
} }
else -> { else -> {
// TODO use some other evaluation here; don't use the estack to transfer the address to read/write from // TODO use some other evaluation here; don't use the estack to transfer the address to read/write from
asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingISub(), target.position)) asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingISub(), target.position))
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1") asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1")
when { when(value.kind) {
valueLv != null -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, valueLv.toInt()) SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.number!!.number.toInt())
ident != null -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, ident) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.asmVarname)
memread != null -> inplaceModification_byte_memread_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, memread) SourceStorageKind.REGISTER -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, regName(value))
value is PtTypeCast -> { SourceStorageKind.MEMORY -> inplaceModification_byte_memread_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.memory!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return SourceStorageKind.ARRAY -> inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.array!!)
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value) SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.expression)
} else {
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.expression!!)
}
} }
else -> inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
asmgen.out(" lda P8ZP_SCRATCH_B1 | jsr prog8_lib.write_byte_to_address_on_stack | inx") asmgen.out(" lda P8ZP_SCRATCH_B1 | jsr prog8_lib.write_byte_to_address_on_stack | inx")
} }
@ -169,38 +198,57 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
val targetVarName = "${target.asmVarname} + ${indexNum.number.toInt()*program.memsizer.memorySize(target.datatype)}" val targetVarName = "${target.asmVarname} + ${indexNum.number.toInt()*program.memsizer.memorySize(target.datatype)}"
when (target.datatype) { when (target.datatype) {
in ByteDatatypes -> { in ByteDatatypes -> {
when { when(value.kind) {
valueLv != null -> inplaceModification_byte_litval_to_variable(targetVarName, target.datatype, operator, valueLv.toInt()) SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable(targetVarName, target.datatype, operator, value.number!!.number.toInt())
ident != null -> inplaceModification_byte_variable_to_variable(targetVarName, target.datatype, operator, ident) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable(targetVarName, target.datatype, operator, value.asmVarname)
memread != null -> inplaceModification_byte_memread_to_variable(targetVarName, target.datatype, operator, memread) SourceStorageKind.REGISTER -> inplaceModification_byte_variable_to_variable(targetVarName, target.datatype, operator, regName(value))
value is PtTypeCast -> { SourceStorageKind.MEMORY -> inplaceModification_byte_memread_to_variable(targetVarName, target.datatype, operator, value.memory!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return SourceStorageKind.ARRAY -> inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value.array!!)
inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value) SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value.expression)
} else {
inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value.expression!!)
}
} }
else -> inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
} }
in WordDatatypes -> { in WordDatatypes -> {
when { when(value.kind) {
valueLv != null -> inplaceModification_word_litval_to_variable(targetVarName, target.datatype, operator, valueLv.toInt()) SourceStorageKind.LITERALNUMBER -> inplaceModification_word_litval_to_variable(targetVarName, target.datatype, operator, value.number!!.number.toInt())
ident != null -> inplaceModification_word_variable_to_variable(targetVarName, target.datatype, operator, ident) SourceStorageKind.VARIABLE -> inplaceModification_word_variable_to_variable(targetVarName, target.datatype, operator, value.asmVarname, value.datatype)
memread != null -> inplaceModification_word_memread_to_variable(targetVarName, target.datatype, operator, memread) SourceStorageKind.REGISTER -> inplaceModification_word_variable_to_variable(targetVarName, target.datatype, operator, regName(value), value.datatype)
value is PtTypeCast -> { SourceStorageKind.MEMORY -> inplaceModification_word_memread_to_variable(targetVarName, target.datatype, operator, value.memory!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return SourceStorageKind.ARRAY -> inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value.array!!)
inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value) SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value.expression)
} else {
inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value.expression!!)
}
} }
else -> inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
} }
DataType.FLOAT -> { DataType.FLOAT -> {
when { when(value.kind) {
valueLv != null -> inplaceModification_float_litval_to_variable(targetVarName, operator, valueLv.toDouble(), target.scope!!) SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(targetVarName, operator, value.number!!.number, target.scope!!)
ident != null -> inplaceModification_float_variable_to_variable(targetVarName, operator, ident, target.scope!!) SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(targetVarName, operator, value.asmVarname, target.scope!!)
value is PtTypeCast -> { SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(targetVarName, operator, regName(value), target.scope!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return SourceStorageKind.MEMORY -> TODO("memread into float array")
inplaceModification_float_value_to_variable(targetVarName, operator, value, target.scope!!) SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(targetVarName, operator, value.array!!, target.scope!!)
SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
inplaceModification_float_value_to_variable(targetVarName, operator, value.expression, target.scope!!)
} else {
inplaceModification_float_value_to_variable(targetVarName, operator, value.expression!!, target.scope!!)
}
} }
else -> inplaceModification_float_value_to_variable(targetVarName, operator, value, target.scope!!) else -> throw AssemblyError("weird source type ${value.kind}")
} }
} }
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
@ -212,16 +260,22 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.UBYTE, CpuRegister.Y) asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.UBYTE, CpuRegister.Y)
asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_B1") asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_B1")
asmgen.saveRegisterLocal(CpuRegister.Y, target.scope!!) asmgen.saveRegisterLocal(CpuRegister.Y, target.scope!!)
when { when(value.kind) {
valueLv != null -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, valueLv.toInt()) SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.number!!.number.toInt())
ident != null -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, ident) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.asmVarname)
memread != null -> inplaceModification_byte_memread_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, memread) SourceStorageKind.REGISTER -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, regName(value))
value is PtTypeCast -> { SourceStorageKind.MEMORY -> inplaceModification_byte_memread_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.memory!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) SourceStorageKind.ARRAY -> inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.array!!)
return SourceStorageKind.EXPRESSION -> {
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value) if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
return
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.expression)
} else {
inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.expression!!)
}
} }
else -> inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
asmgen.restoreRegisterLocal(CpuRegister.Y) asmgen.restoreRegisterLocal(CpuRegister.Y)
asmgen.out(" lda P8ZP_SCRATCH_B1 | sta ${target.array.variable.name},y") asmgen.out(" lda P8ZP_SCRATCH_B1 | sta ${target.array.variable.name},y")
@ -231,16 +285,22 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_W1") asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_W1")
asmgen.out(" iny | lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_W1+1") asmgen.out(" iny | lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_W1+1")
asmgen.saveRegisterLocal(CpuRegister.Y, target.scope!!) asmgen.saveRegisterLocal(CpuRegister.Y, target.scope!!)
when { when(value.kind) {
valueLv != null -> inplaceModification_word_litval_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, valueLv.toInt()) SourceStorageKind.LITERALNUMBER -> inplaceModification_word_litval_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.number!!.number.toInt())
ident != null -> inplaceModification_word_variable_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, ident) SourceStorageKind.VARIABLE -> inplaceModification_word_variable_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.asmVarname, value.datatype)
memread != null -> inplaceModification_word_memread_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, memread) SourceStorageKind.REGISTER -> inplaceModification_word_variable_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, regName(value), value.datatype)
value is PtTypeCast -> { SourceStorageKind.MEMORY -> inplaceModification_word_memread_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.memory!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) SourceStorageKind.ARRAY -> inplaceModification_word_value_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.array!!)
return SourceStorageKind.EXPRESSION -> {
inplaceModification_word_value_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value) if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
return
inplaceModification_word_value_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression)
} else {
inplaceModification_word_value_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression!!)
}
} }
else -> inplaceModification_word_value_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value) else -> throw AssemblyError("weird source type ${value.kind}")
} }
asmgen.restoreRegisterLocal(CpuRegister.Y) asmgen.restoreRegisterLocal(CpuRegister.Y)
asmgen.out(" lda P8ZP_SCRATCH_W1+1 | sta ${target.array.variable.name},y") asmgen.out(" lda P8ZP_SCRATCH_W1+1 | sta ${target.array.variable.name},y")
@ -260,15 +320,22 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
lda #<$tempvar lda #<$tempvar
ldy #>$tempvar ldy #>$tempvar
jsr floats.copy_float""") // copy from array into float temp var, clobbers A,Y jsr floats.copy_float""") // copy from array into float temp var, clobbers A,Y
when { when(value.kind) {
valueLv != null -> inplaceModification_float_litval_to_variable(tempvar, operator, valueLv, target.scope!!) SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(tempvar, operator, value.number!!.number, target.scope!!)
ident != null -> inplaceModification_float_variable_to_variable(tempvar, operator, ident, target.scope!!) SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(tempvar, operator, value.asmVarname, target.scope!!)
value is PtTypeCast -> { SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(tempvar, operator, regName(value), target.scope!!)
if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) SourceStorageKind.MEMORY -> TODO("memread into float")
return SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(tempvar, operator, value.array!!, target.scope!!)
inplaceModification_float_value_to_variable(tempvar, operator, value, target.scope!!) SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
return
inplaceModification_float_value_to_variable(tempvar, operator, value.expression, target.scope!!)
} else {
inplaceModification_float_value_to_variable(tempvar, operator, value.expression!!, target.scope!!)
}
} }
else -> inplaceModification_float_value_to_variable(tempvar, operator, value, target.scope!!) else -> throw AssemblyError("weird source type ${value.kind}")
} }
asmgen.out(""" asmgen.out("""
lda P8ZP_SCRATCH_W1 lda P8ZP_SCRATCH_W1
@ -300,7 +367,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
if (value.type!=DataType.FLOAT && (value.type.equalsSize(childDt) || value.type.largerThan(childDt))) { if (value.type!=DataType.FLOAT && (value.type.equalsSize(childDt) || value.type.largerThan(childDt))) {
// this typecast is redundant here; the rest of the code knows how to deal with the uncasted value. // this typecast is redundant here; the rest of the code knows how to deal with the uncasted value.
// (works for integer types, not for float.) // (works for integer types, not for float.)
inplaceModification(target, operator, value.value) val src = AsmAssignSource.fromAstSource(value.value, program, asmgen)
inplaceModification(target, operator, src)
return true return true
} }
} }
@ -362,8 +430,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.storeAIntoZpPointerVar(sourceName) asmgen.storeAIntoZpPointerVar(sourceName)
} }
private fun inplaceModification_byte_variable_to_pointer(pointervar: PtIdentifier, operator: String, value: PtIdentifier) { private fun inplaceModification_byte_variable_to_pointer(pointervar: PtIdentifier, operator: String, otherName: String) {
val otherName = asmgen.asmVariableName(value)
val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) val sourceName = asmgen.loadByteFromPointerIntoA(pointervar)
when (operator) { when (operator) {
@ -643,8 +710,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
} }
} }
private fun inplaceModification_byte_variable_to_variable(name: String, dt: DataType, operator: String, ident: PtIdentifier) { private fun inplaceModification_byte_variable_to_variable(name: String, dt: DataType, operator: String, otherName: String) {
val otherName = asmgen.asmVariableName(ident)
when (operator) { when (operator) {
"+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name") "+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name")
"-" -> asmgen.out(" lda $name | sec | sbc $otherName | sta $name") "-" -> asmgen.out(" lda $name | sec | sbc $otherName | sta $name")
@ -1259,9 +1325,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
} }
} }
private fun inplaceModification_word_variable_to_variable(name: String, dt: DataType, operator: String, ident: PtIdentifier) { private fun inplaceModification_word_variable_to_variable(name: String, dt: DataType, operator: String, otherName: String, valueDt: DataType) {
val otherName = asmgen.asmVariableName(ident) when (valueDt) {
when (val valueDt = ident.type) {
in ByteDatatypes -> { in ByteDatatypes -> {
// the other variable is a BYTE type so optimize for that // the other variable is a BYTE type so optimize for that
when (operator) { when (operator) {
@ -1450,7 +1515,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
sta $name+1""") sta $name+1""")
} }
// pretty uncommon, who's going to assign a comparison boolean expresion to a word var?: // pretty uncommon, who's going to assign a comparison boolean expresion to a word var?:
"<", "<=", ">", ">=" -> TODO("word-bytevar-to-var comparisons ${ident.position}") "<", "<=", ">", ">=" -> TODO("word-bytevar-to-var comparisons")
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
} }
@ -1957,12 +2022,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.restoreRegisterLocal(CpuRegister.X) asmgen.restoreRegisterLocal(CpuRegister.X)
} }
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: PtIdentifier, scope: IPtSubroutine) { private fun inplaceModification_float_variable_to_variable(name: String, operator: String, otherName: String, scope: IPtSubroutine) {
val valueDt = ident.type
if(valueDt != DataType.FLOAT)
throw AssemblyError("float variable expected")
val otherName = asmgen.asmVariableName(ident)
asmgen.saveRegisterLocal(CpuRegister.X, scope) asmgen.saveRegisterLocal(CpuRegister.X, scope)
when (operator) { when (operator) {
"+" -> { "+" -> {
@ -2082,49 +2142,3 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.restoreRegisterLocal(CpuRegister.X) asmgen.restoreRegisterLocal(CpuRegister.X)
} }
} }
private fun AsmAssignSource.toAstExpression(scope: PtNamedNode): PtExpression {
return when(kind) {
SourceStorageKind.LITERALNUMBER -> this.number!!
SourceStorageKind.VARIABLE -> {
val ident = PtIdentifier(scope.scopedName + '.' + asmVarname, datatype, Position.DUMMY)
ident.parent = scope
ident
}
SourceStorageKind.ARRAY -> this.array!!
SourceStorageKind.MEMORY -> this.memory!!
SourceStorageKind.EXPRESSION -> this.expression!!
SourceStorageKind.REGISTER -> {
if(register in Cx16VirtualRegisters) {
val ident = PtIdentifier("cx16.${register!!.name.lowercase()}", DataType.UWORD, position = scope.position)
ident.parent = scope
ident
} else {
throw AssemblyError("no ast expr possible for source register $register")
}
}
else -> throw AssemblyError("invalid assign source kind $kind")
}
}
private fun AsmAssignTarget.toAstExpression(): PtExpression {
return when(kind) {
TargetStorageKind.VARIABLE -> {
val ident = PtIdentifier((this.scope as PtNamedNode).scopedName + '.' + asmVarname, datatype, position)
ident.parent = this.scope
ident
}
TargetStorageKind.ARRAY -> this.array!!
TargetStorageKind.MEMORY -> this.memory!!
TargetStorageKind.REGISTER -> {
if(register in Cx16VirtualRegisters) {
val ident = PtIdentifier("cx16.${register!!.name.lowercase()}", DataType.UWORD, position)
ident.parent = (this.scope as? PtNamedNode) ?: this.origAstTarget!!
ident
} else {
throw AssemblyError("no ast expr possible for target register $register")
}
}
else -> throw AssemblyError("invalid assign target kind $kind")
}
}