From 76c95ba6fa0260bb14bd407ac080e2bf4aa879da Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 5 Dec 2025 20:25:56 +0100 Subject: [PATCH] some more obscure inplace modifications implemented --- .../assignment/AugmentableAssignmentAsmGen.kt | 214 ++------------ .../assignment/PointerAssignmentsGen.kt | 269 ++++++++++++++++-- docs/source/todo.rst | 1 + 3 files changed, 255 insertions(+), 229 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index f9a807bf6..e0346a3a2 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -113,9 +113,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, SourceStorageKind.LITERALNUMBER -> inplacemodificationLongWithLiteralval(target.asmVarname, operator, value.number!!.number.toInt()) SourceStorageKind.VARIABLE -> inplacemodificationLongWithVariable(target.asmVarname, operator, value.asmVarname) SourceStorageKind.EXPRESSION -> inplacemodificationLongWithExpression(target.asmVarname, operator, value.expression!!) - SourceStorageKind.REGISTER -> TODO("32 bits register inplace modification? ${target.position}") - SourceStorageKind.ARRAY -> TODO("inplace modify long with array ${target.position}") - SourceStorageKind.MEMORY -> TODO("memread into long ${target.position}") + SourceStorageKind.REGISTER -> inplacemodificationLongWithVariable(target.asmVarname, operator, regName(value)) + SourceStorageKind.ARRAY -> TODO("inplace modify long with array value ${target.position}") + SourceStorageKind.MEMORY -> TODO("inplace modify long with memread value ${target.position}") } } target.datatype.isFloat -> { @@ -124,7 +124,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(target.asmVarname, operator, value.number!!.number) SourceStorageKind.VARIABLE -> inplacemodificationFloatWithVariable(target.asmVarname, operator, value.asmVarname) SourceStorageKind.REGISTER -> inplacemodificationFloatWithVariable(target.asmVarname, operator, regName(value)) - SourceStorageKind.MEMORY -> TODO("memread into float ${target.position}") + SourceStorageKind.MEMORY -> inplacemodificationFloatWithValue(target.asmVarname, operator, value.memory!!) SourceStorageKind.ARRAY -> inplacemodificationFloatWithValue(target.asmVarname, operator, value.array!!) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { @@ -164,18 +164,18 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, is PtIdentifier -> { val pointer = memory.address as PtIdentifier when(value.kind) { - SourceStorageKind.LITERALBOOLEAN -> inplacemodificationBytePointerWithLiteralval(pointer, operator, value.boolean!!.asInt()) - SourceStorageKind.LITERALNUMBER -> inplacemodificationBytePointerWithLiteralval(pointer, operator, value.number!!.number.toInt()) - SourceStorageKind.VARIABLE -> inplacemodificationBytePointerWithVariable(pointer, operator, value.asmVarname) - SourceStorageKind.REGISTER -> inplacemodificationBytePointerWithVariable(pointer, operator, regName(value)) - SourceStorageKind.MEMORY -> TODO("memread into pointer ${target.position}") - SourceStorageKind.ARRAY -> inplacemodificationBytePointerWithValue(pointer, operator, value.array!!) + SourceStorageKind.LITERALBOOLEAN -> ptrgen.inplacemodificationBytePointerWithLiteralval(pointer, operator, value.boolean!!.asInt()) + SourceStorageKind.LITERALNUMBER -> ptrgen.inplacemodificationBytePointerWithLiteralval(pointer, operator, value.number!!.number.toInt()) + SourceStorageKind.VARIABLE -> ptrgen.inplacemodificationBytePointerWithVariable(pointer, operator, value.asmVarname) + SourceStorageKind.REGISTER -> ptrgen.inplacemodificationBytePointerWithVariable(pointer, operator, regName(value)) + SourceStorageKind.MEMORY -> ptrgen. inplacemodificationBytePointerWithValue(pointer, operator, value.memory!!) + SourceStorageKind.ARRAY -> ptrgen.inplacemodificationBytePointerWithValue(pointer, operator, value.array!!) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return - inplacemodificationBytePointerWithValue(pointer, operator, value.expression) + ptrgen.inplacemodificationBytePointerWithValue(pointer, operator, value.expression) } else { - inplacemodificationBytePointerWithValue(pointer, operator, value.expression!!) + ptrgen.inplacemodificationBytePointerWithValue(pointer, operator, value.expression!!) } } } @@ -309,8 +309,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, SourceStorageKind.LITERALNUMBER -> inplacemodificationLongWithLiteralval(targetVarName, operator, value.number!!.number.toInt()) SourceStorageKind.VARIABLE -> inplacemodificationLongWithVariable(targetVarName, operator, value.asmVarname) SourceStorageKind.REGISTER -> inplacemodificationLongWithVariable(targetVarName, operator, regName(value)) - SourceStorageKind.MEMORY -> TODO("inplace long modifiication ${target.position}") - SourceStorageKind.ARRAY -> TODO("inplace long modifiication ${target.position}") + SourceStorageKind.MEMORY -> TODO("inplace long modifiication with memread value ${target.position}") + SourceStorageKind.ARRAY -> TODO("inplace long modifiication with array value ${target.position}") SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return @@ -328,7 +328,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(targetVarName, operator, value.number!!.number) SourceStorageKind.VARIABLE -> inplacemodificationFloatWithVariable(targetVarName, operator, value.asmVarname) SourceStorageKind.REGISTER -> inplacemodificationFloatWithVariable(targetVarName, operator, regName(value)) - SourceStorageKind.MEMORY -> TODO("memread into float array ${target.position}") + SourceStorageKind.MEMORY -> inplacemodificationFloatWithValue(targetVarName, operator, value.memory!!) SourceStorageKind.ARRAY -> inplacemodificationFloatWithValue(targetVarName, operator, value.array!!) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { @@ -519,7 +519,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(tempvar, operator, value.number!!.number) SourceStorageKind.VARIABLE -> inplacemodificationFloatWithVariable(tempvar, operator, value.asmVarname) SourceStorageKind.REGISTER -> inplacemodificationFloatWithVariable(tempvar, operator, regName(value)) - SourceStorageKind.MEMORY -> TODO("memread into float ${target.position}") + SourceStorageKind.MEMORY -> inplacemodificationFloatWithValue(tempvar, operator, value.memory!!) SourceStorageKind.ARRAY -> inplacemodificationFloatWithValue(tempvar, operator, value.array!!) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { @@ -1406,188 +1406,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, return false } - private fun inplacemodificationBytePointerWithValue(pointervar: PtIdentifier, operator: String, value: PtExpression) { - asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.UBYTE) - inplacemodificationBytePointerWithVariable(pointervar, operator, "P8ZP_SCRATCH_B1") - } - - private fun inplacemodificationBytePointerWithVariable(pointervar: PtIdentifier, operator: String, otherName: String) { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - - when (operator) { - "+" -> asmgen.out(" clc | adc $otherName") - "-" -> asmgen.out(" sec | sbc $otherName") - "*" -> asmgen.out(" ldy $otherName | jsr prog8_math.multiply_bytes") - "/" -> asmgen.out(" ldy $otherName | jsr prog8_math.divmod_ub_asm | tya") - "%" -> asmgen.out(" ldy $otherName | jsr prog8_math.remainder_ub_asm") - "<<" -> { - asmgen.out(""" - ldy $otherName - beq + -- asl a - dey - bne - -+""") - } - ">>" -> { - asmgen.out(""" - ldy $otherName - beq + -- lsr a - dey - bne - -+""") - } - "&" -> asmgen.out(" and $otherName") - "|" -> asmgen.out(" ora $otherName") - "^" -> asmgen.out(" eor $otherName") - "==" -> { - asmgen.out(""" - cmp $otherName - beq + - lda #0 - beq ++ -+ lda #1 -+""") - } - "!=" -> { - asmgen.out(""" - cmp $otherName - bne + - lda #0 - beq ++ -+ lda #1 -+""") - } - // pretty uncommon, who's going to assign a comparison boolean expression to a pointer? - "<", "<=", ">", ">=" -> TODO("byte-var-to-pointer comparisons ${pointervar.position}") - else -> throw AssemblyError("invalid operator for in-place modification $operator") - } - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - - private fun inplacemodificationBytePointerWithLiteralval(pointervar: PtIdentifier, operator: String, value: Int) { - // note: this contains special optimized cases because we know the exact value. Don't replace this with another routine. - when (operator) { - "+" -> { - if(value==1) { - if(asmgen.options.romable) { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - if(asmgen.isTargetCpu(CpuType.CPU65C02)) - asmgen.out(" inc a") - else - asmgen.out(" clc | adc #1") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } else { - asmgen.assignExpressionToRegister(pointervar, RegisterOrPair.AY) - asmgen.out(" sta (+) + 1 | sty (+) + 2") - asmgen.out($$"+\tinc $ffff\t; modified") - } - } else { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - asmgen.out(" clc | adc #$value") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - } - "-" -> { - if(value==1) { - if(asmgen.options.romable) { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - if(asmgen.isTargetCpu(CpuType.CPU65C02)) - asmgen.out(" dec a") - else - asmgen.out(" sec | sbc #1") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } else { - asmgen.assignExpressionToRegister(pointervar, RegisterOrPair.AY) - asmgen.out(" sta (+) + 1 | sty (+) + 2") - asmgen.out($$"+\tdec $ffff\t; modified") - } - } else { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - asmgen.out(" sec | sbc #$value") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - } - "*" -> { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - if(value in asmgen.optimizedByteMultiplications) - asmgen.out(" jsr prog8_math.mul_byte_${value}") - else - asmgen.out(" ldy #$value | jsr prog8_math.multiply_bytes") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - "/" -> { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - if(value==0) - throw AssemblyError("division by zero") - asmgen.out(" ldy #$value | jsr prog8_math.divmod_ub_asm | tya") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - "%" -> { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - if(value==0) - throw AssemblyError("division by zero") - asmgen.out(" ldy #$value | jsr prog8_math.remainder_ub_asm") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - "<<" -> { - if (value > 0) { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - repeat(value) { asmgen.out(" asl a") } - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - } - ">>" -> { - if (value > 0) { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - repeat(value) { asmgen.out(" lsr a") } - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - } - "&" -> { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - asmgen.out(" and #$value") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - "|"-> { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - asmgen.out(" ora #$value") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - "^" -> { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - asmgen.out(" eor #$value") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - "==" -> { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - asmgen.out(""" - cmp #$value - beq + - lda #0 - beq ++ -+ lda #1 -+""") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - "!=" -> { - val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) - asmgen.out(""" - cmp #$value - bne + - lda #0 - beq ++ -+ lda #1 -+""") - asmgen.storeAIntoZpPointerVar(sourceName, false) - } - // pretty uncommon, who's going to assign a comparison boolean expression to a pointer?: - "<", "<=", ">", ">=" -> TODO("byte-litval-to-pointer comparisons ${pointervar.position}") - else -> throw AssemblyError("invalid operator for in-place modification $operator") - } - } - private fun inplacemodificationByteWithValue(name: String, dt: DataType, operator: String, value: PtExpression) { require(dt.isByteOrBool) if(!value.isSimple()) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt index ee1ed4a95..ef6ac60ac 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt @@ -288,52 +288,76 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri } } "*" -> { - if(target.dt.isByte) TODO("inplaceByteMul(target, value) ${target.position}") - else if(target.dt.isWord) inplaceWordMul(target, value) - else if(target.dt.isFloat) inplaceFloatAddOrMul(target, "FMULT", value) - else if(target.dt.isLong) TODO("inplace long mul ${target.position}") - else throw AssemblyError("weird dt ${target.position}") + when { + target.dt.isByte -> TODO("inplaceByteMul(target, value) ${target.position}") + target.dt.isWord -> inplaceWordMul(target, value) + target.dt.isFloat -> inplaceFloatAddOrMul(target, "FMULT", value) + target.dt.isLong -> TODO("inplace long mul ${target.position}") + else -> throw AssemblyError("weird dt ${target.position}") + } } "/" -> { - if(target.dt.isByte) TODO("inplaceByteDiv(target, value) ${target.position}") - else if(target.dt.isWord) inplaceWordDiv(target, value) - else if(target.dt.isFloat) inplaceFloatSubOrDiv(target, "FDIV", value) - else if(target.dt.isLong) TODO("inplace long div ${target.position}") - else throw AssemblyError("weird dt ${target.position}") + when { + target.dt.isByte -> TODO("inplaceByteDiv(target, value) ${target.position}") + target.dt.isWord -> inplaceWordDiv(target, value) + target.dt.isFloat -> inplaceFloatSubOrDiv(target, "FDIV", value) + target.dt.isLong -> TODO("inplace long div ${target.position}") + else -> throw AssemblyError("weird dt ${target.position}") + } + } + "%" -> { + if(target.dt.isSigned || value.datatype.isSigned) + throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") + when { + target.dt.isByte -> TODO("inplace byte pointer mod should have been handled via MEMORY target type ${target.position}") + target.dt.isWord -> TODO("inplace word pointer mod ${target.position}") + //target.dt.isFloat -> TODO("inplace float pointer mod ${target.position}") + //target.dt.isLong -> TODO("inplace long pointer mod ${target.position}") + else -> throw AssemblyError("weird dt ${target.position}") + } } - "%" -> TODO("inplace ptr % ${target.position}") "<<" -> { - if(target.dt.isByte) inplaceByteShiftLeft(target, value) - else if(target.dt.isWord) inplaceWordShiftLeft(target, value) - else if(target.dt.isLong) inplaceLongShiftLeft(target, value) - else throw AssemblyError("weird dt ${target.position}") + when { + target.dt.isByte -> inplaceByteShiftLeft(target, value) + target.dt.isWord -> inplaceWordShiftLeft(target, value) + target.dt.isLong -> inplaceLongShiftLeft(target, value) + else -> throw AssemblyError("weird dt ${target.position}") + } } ">>" -> { - if(target.dt.isByte) inplaceByteShiftRight(target, value) - else if(target.dt.isWord) inplaceWordShiftRight(target, value) - else if(target.dt.isLong) inplaceLongShiftRight(target, value) - else throw AssemblyError("weird dt ${target.position}") + when { + target.dt.isByte -> inplaceByteShiftRight(target, value) + target.dt.isWord -> inplaceWordShiftRight(target, value) + target.dt.isLong -> inplaceLongShiftRight(target, value) + else -> throw AssemblyError("weird dt ${target.position}") + } } "&", "and" -> { // byte targets are handled as direct memory access, not a pointer operation anymore however boolean targets are still to be handled here - if(target.dt.isByteOrBool) inplaceByteAnd(target, value) - else if(target.dt.isWord) inplaceWordAnd(target, value) - else if(target.dt.isLong) inplaceLongAnd(target, value) - else throw AssemblyError("weird dt ${target.dt} ${target.position}") + when { + target.dt.isByteOrBool -> inplaceByteAnd(target, value) + target.dt.isWord -> inplaceWordAnd(target, value) + target.dt.isLong -> inplaceLongAnd(target, value) + else -> throw AssemblyError("weird dt ${target.dt} ${target.position}") + } } "|", "or" -> { // byte targets are handled as direct memory access, not a pointer operation anymore however boolean targets are still to be handled here - if(target.dt.isByteOrBool) inplaceByteOr(target, value) - else if(target.dt.isWord) inplaceWordOr(target, value) - else if(target.dt.isLong) inplaceLongOr(target, value) - else throw AssemblyError("weird dt ${target.dt} ${target.position}") + when { + target.dt.isByteOrBool -> inplaceByteOr(target, value) + target.dt.isWord -> inplaceWordOr(target, value) + target.dt.isLong -> inplaceLongOr(target, value) + else -> throw AssemblyError("weird dt ${target.dt} ${target.position}") + } } "^", "xor" -> { // byte targets are handled as direct memory access, not a pointer operation anymore however boolean targets are still to be handled here - if(target.dt.isByteOrBool) inplaceByteXor(target, value) - else if(target.dt.isWord) inplaceWordXor(target, value) - else if(target.dt.isLong) inplaceLongXor(target, value) - else throw AssemblyError("weird dt ${target.dt} ${target.position}") + when { + target.dt.isByteOrBool -> inplaceByteXor(target, value) + target.dt.isWord -> inplaceWordXor(target, value) + target.dt.isLong -> inplaceLongXor(target, value) + else -> throw AssemblyError("weird dt ${target.dt} ${target.position}") + } } else -> throw AssemblyError("invalid operator for in-place modification $operator") } @@ -501,6 +525,189 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri sta ($ptrVar),y""") } + internal fun inplacemodificationBytePointerWithValue(pointervar: PtIdentifier, operator: String, value: PtExpression) { + asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.UBYTE) + inplacemodificationBytePointerWithVariable(pointervar, operator, "P8ZP_SCRATCH_B1") + } + + internal fun inplacemodificationBytePointerWithVariable(pointervar: PtIdentifier, operator: String, otherName: String) { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + + when (operator) { + "+" -> asmgen.out(" clc | adc $otherName") + "-" -> asmgen.out(" sec | sbc $otherName") + "*" -> asmgen.out(" ldy $otherName | jsr prog8_math.multiply_bytes") + "/" -> asmgen.out(" ldy $otherName | jsr prog8_math.divmod_ub_asm | tya") + "%" -> asmgen.out(" ldy $otherName | jsr prog8_math.remainder_ub_asm") + "<<" -> { + asmgen.out(""" + ldy $otherName + beq + +- asl a + dey + bne - ++""") + } + ">>" -> { + asmgen.out(""" + ldy $otherName + beq + +- lsr a + dey + bne - ++""") + } + "&" -> asmgen.out(" and $otherName") + "|" -> asmgen.out(" ora $otherName") + "^" -> asmgen.out(" eor $otherName") + "==" -> { + asmgen.out(""" + cmp $otherName + beq + + lda #0 + beq ++ ++ lda #1 ++""") + } + "!=" -> { + asmgen.out(""" + cmp $otherName + bne + + lda #0 + beq ++ ++ lda #1 ++""") + } + // pretty uncommon, who's going to assign a comparison boolean expression to a pointer? + "<", "<=", ">", ">=" -> TODO("byte-var-to-pointer comparisons ${pointervar.position}") + else -> throw AssemblyError("invalid operator for in-place modification $operator") + } + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + + internal fun inplacemodificationBytePointerWithLiteralval(pointervar: PtIdentifier, operator: String, value: Int) { + // note: this contains special optimized cases because we know the exact value. Don't replace this with another routine. + when (operator) { + "+" -> { + if(value==1) { + if(asmgen.options.romable) { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + if(asmgen.isTargetCpu(CpuType.CPU65C02)) + asmgen.out(" inc a") + else + asmgen.out(" clc | adc #1") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } else { + asmgen.assignExpressionToRegister(pointervar, RegisterOrPair.AY) + asmgen.out(" sta (+) + 1 | sty (+) + 2") + asmgen.out($$"+\tinc $ffff\t; modified") + } + } else { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + asmgen.out(" clc | adc #$value") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + } + "-" -> { + if(value==1) { + if(asmgen.options.romable) { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + if(asmgen.isTargetCpu(CpuType.CPU65C02)) + asmgen.out(" dec a") + else + asmgen.out(" sec | sbc #1") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } else { + asmgen.assignExpressionToRegister(pointervar, RegisterOrPair.AY) + asmgen.out(" sta (+) + 1 | sty (+) + 2") + asmgen.out($$"+\tdec $ffff\t; modified") + } + } else { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + asmgen.out(" sec | sbc #$value") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + } + "*" -> { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + if(value in asmgen.optimizedByteMultiplications) + asmgen.out(" jsr prog8_math.mul_byte_${value}") + else + asmgen.out(" ldy #$value | jsr prog8_math.multiply_bytes") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + "/" -> { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + if(value==0) + throw AssemblyError("division by zero") + asmgen.out(" ldy #$value | jsr prog8_math.divmod_ub_asm | tya") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + "%" -> { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + if(value==0) + throw AssemblyError("division by zero") + asmgen.out(" ldy #$value | jsr prog8_math.remainder_ub_asm") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + "<<" -> { + if (value > 0) { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + repeat(value) { asmgen.out(" asl a") } + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + } + ">>" -> { + if (value > 0) { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + repeat(value) { asmgen.out(" lsr a") } + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + } + "&" -> { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + asmgen.out(" and #$value") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + "|"-> { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + asmgen.out(" ora #$value") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + "^" -> { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + asmgen.out(" eor #$value") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + "==" -> { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + asmgen.out(""" + cmp #$value + beq + + lda #0 + beq ++ ++ lda #1 ++""") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + "!=" -> { + val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) + asmgen.out(""" + cmp #$value + bne + + lda #0 + beq ++ ++ lda #1 ++""") + asmgen.storeAIntoZpPointerVar(sourceName, false) + } + // pretty uncommon, who's going to assign a comparison boolean expression to a pointer?: + "<", "<=", ">", ">=" -> TODO("byte-litval-to-pointer comparisons ${pointervar.position}") + else -> throw AssemblyError("invalid operator for in-place modification $operator") + } + } + + internal fun operatorDereference(binExpr: PtBinaryExpression): Triple { // the only case we support here is: a.b.c[i] . value diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 2d9ab3274..d66f919e8 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -26,6 +26,7 @@ Future Things and Ideas - struct/ptr: really fixing the pointer dereferencing issues (cursed hybrid beween IdentifierReference, PtrDereferece and PtrIndexedDereference) may require getting rid of scoped identifiers altogether and treat '.' as a "scope or pointer following operator" - struct/ptr: (later, nasty parser problem:) support chaining pointer dereference on function calls that return a pointer. (type checking now fails on stuff like func().field and func().next.field) - structs: properly fix the symbol name prefix hack in StStruct.sameas(), see github issue 198 +- should we have a SourceStorageKind.POINTER? (there is one for TargetStorageKind...) - array-as-param bug: printf([1111,2,3,-4444]) gives argument type mismatch (param is of type uword), while printf([1111,2,3,4444]) just works fine (passes address of @nosplit array) - make memory mapped variables support more constant expressions such as: &uword MyHigh = &mylong1+2 - allow memory() to occur in array initializer (maybe needed for 2 dimensional arrays?) i.e. make it a constant (see github issue #192)