From a0deb463c9ac98a70b571ccfdd1489bb3ed23441 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 31 Jul 2022 13:38:00 +0200 Subject: [PATCH] optimized codegen for some equality comparison expressions and some logical expressions --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 2 +- .../codegen/cpu6502/BuiltinFunctionsAsmGen.kt | 20 +- .../codegen/cpu6502/FunctionCallAsmGen.kt | 4 +- .../codegen/cpu6502/ProgramAndVarsGen.kt | 6 +- .../cpu6502/assignment/AsmAssignment.kt | 19 +- .../cpu6502/assignment/AssignmentAsmGen.kt | 354 +++++++++++------- .../assignment/AugmentableAssignmentAsmGen.kt | 5 +- docs/source/todo.rst | 2 - examples/test.p8 | 49 ++- 9 files changed, 282 insertions(+), 179 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 9bbf8e42b..292d8f399 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -2874,7 +2874,7 @@ $repeatLabel lda $counterVar } } } else { - val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, target.datatype, scope, variableAsmName = asmVariableName(target.scopedName)) + val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, this, target.datatype, scope, variableAsmName = asmVariableName(target.scopedName)) if (dt in ByteDatatypes) { out(" pla") assignRegister(RegisterOrPair.A, tgt) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 05f5d5380..1cab673b2 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -321,9 +321,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = AddressOf(slabname, fcall.position)) val target = if(resultToStack) - AsmAssignTarget(TargetStorageKind.STACK, program, asmgen, DataType.UWORD, null) + AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, null) else - AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, null, program, asmgen) + AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, null, asmgen) val assign = AsmAssignment(src, target, false, program.memsizer, fcall.position) asmgen.translateNormalAssignment(assign) allocations.allocateMemorySlab(name, size, align) @@ -335,7 +335,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, asmgen.out(" jsr prog8_lib.func_sqrt16_stack") else { asmgen.out(" jsr prog8_lib.func_sqrt16_into_A") - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, program, asmgen), CpuRegister.A) + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, asmgen), CpuRegister.A) } } @@ -648,7 +648,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A") else -> throw AssemblyError("weird type $dt") } - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, program, asmgen), CpuRegister.A) + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, asmgen), CpuRegister.A) } } @@ -669,7 +669,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_into_A | ldy #0") else -> throw AssemblyError("weird type $dt") } - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, program, asmgen), CpuRegister.A) + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, asmgen), CpuRegister.A) } } @@ -692,7 +692,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, DataType.WORD -> asmgen.out(" jsr prog8_lib.abs_w_into_AY") else -> throw AssemblyError("weird type") } - assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY) + assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, asmgen), RegisterOrPair.AY) } } @@ -703,7 +703,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, asmgen.out(" jsr prog8_lib.func_rnd_stack") else { asmgen.out(" jsr math.randbyte") - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, program, asmgen), CpuRegister.A) + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, asmgen), CpuRegister.A) } } "rndw" -> { @@ -711,7 +711,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, asmgen.out(" jsr prog8_lib.func_rndw_stack") else { asmgen.out(" jsr math.randword") - assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY) + assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, asmgen), RegisterOrPair.AY) } } else -> throw AssemblyError("wrong func") @@ -1084,7 +1084,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, AsmAssignSource.fromAstSource(value, program, asmgen) } } - val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, conv.dt, null, variableAsmName = varname) + val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, conv.dt, null, variableAsmName = varname) val assign = AsmAssignment(src, tgt, false, program.memsizer, value.position) asmgen.translateNormalAssignment(assign) } @@ -1100,7 +1100,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, AsmAssignSource.fromAstSource(value, program, asmgen) } } - val tgt = AsmAssignTarget.fromRegisters(conv.reg!!, false, null, program, asmgen) + val tgt = AsmAssignTarget.fromRegisters(conv.reg!!, false, null, asmgen) val assign = AsmAssignment(src, tgt, false, program.memsizer, value.position) asmgen.translateNormalAssignment(assign) } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index 68082a768..bb58a46e6 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -234,10 +234,10 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg } else { val target: AsmAssignTarget = if(parameter.value.type in ByteDatatypes && (register==RegisterOrPair.AX || register == RegisterOrPair.AY || register==RegisterOrPair.XY || register in Cx16VirtualRegisters)) - AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, parameter.value.type, sub, register = register) + AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, parameter.value.type, sub, register = register) else { val signed = parameter.value.type == DataType.BYTE || parameter.value.type == DataType.WORD - AsmAssignTarget.fromRegisters(register, signed, sub, program, asmgen) + AsmAssignTarget.fromRegisters(register, signed, sub, asmgen) } val src = if(valueDt in PassByReferenceDatatypes) { if(value is IdentifierReference) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 9b887a777..09463c027 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -308,7 +308,7 @@ internal class ProgramAndVarsGen( asmgen.out("; simple int arg(s) passed via register(s)") if(sub.parameters.size==1) { val dt = sub.parameters[0].type - val target = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, sub, variableAsmName = sub.parameters[0].name) + val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, sub, variableAsmName = sub.parameters[0].name) if(dt in ByteDatatypes) asmgen.assignRegister(RegisterOrPair.A, target) else @@ -316,8 +316,8 @@ internal class ProgramAndVarsGen( } else { require(sub.parameters.size==2) // 2 simple byte args, first in A, second in Y - val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, sub.parameters[0].type, sub, variableAsmName = sub.parameters[0].name) - val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, sub.parameters[1].type, sub, variableAsmName = sub.parameters[1].name) + val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, sub.parameters[0].type, sub, variableAsmName = sub.parameters[0].name) + val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, sub.parameters[1].type, sub, variableAsmName = sub.parameters[1].name) asmgen.assignRegister(RegisterOrPair.A, target1) asmgen.assignRegister(RegisterOrPair.Y, target2) } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index 59534babc..627a1db3a 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -29,7 +29,6 @@ internal enum class SourceStorageKind { } internal class AsmAssignTarget(val kind: TargetStorageKind, - private val program: Program, private val asmgen: AsmGen, val datatype: DataType, val scope: Subroutine?, @@ -70,28 +69,28 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, if(reg.statusflag!=null) throw AssemblyError("can't assign value to processor statusflag directly") else - return AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, dt, assign.definingSubroutine, register=reg.registerOrPair, origAstTarget = this) + return AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, assign.definingSubroutine, register=reg.registerOrPair, origAstTarget = this) } } - return AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this) + return AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this) } - arrayindexed != null -> return AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this) - memoryAddress != null -> return AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, dt, assign.definingSubroutine, memory = memoryAddress, origAstTarget = this) + arrayindexed != null -> return AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this) + memoryAddress != null -> return AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, dt, assign.definingSubroutine, memory = memoryAddress, origAstTarget = this) else -> throw AssemblyError("weird target") } } } - fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: Subroutine?, program: Program, asmgen: AsmGen): AsmAssignTarget = + fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: Subroutine?, asmgen: AsmGen): AsmAssignTarget = when(registers) { RegisterOrPair.A, RegisterOrPair.X, - RegisterOrPair.Y -> AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, if(signed) DataType.BYTE else DataType.UBYTE, scope, register = registers) + RegisterOrPair.Y -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.BYTE else DataType.UBYTE, scope, register = registers) RegisterOrPair.AX, RegisterOrPair.AY, - RegisterOrPair.XY -> AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, register = registers) + RegisterOrPair.XY -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, register = registers) RegisterOrPair.FAC1, - RegisterOrPair.FAC2 -> AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, DataType.FLOAT, scope, register = registers) + RegisterOrPair.FAC2 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.FLOAT, scope, register = registers) RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, @@ -107,7 +106,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, - RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, register = registers) + RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, register = registers) } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index fe2151f83..6649b5f75 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -29,7 +29,7 @@ internal class AssignmentAsmGen(private val program: Program, internal fun virtualRegsToVariables(origtarget: AsmAssignTarget): AsmAssignTarget { return if(origtarget.kind==TargetStorageKind.REGISTER && origtarget.register in Cx16VirtualRegisters) { - AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, origtarget.datatype, origtarget.scope, + AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, origtarget.datatype, origtarget.scope, variableAsmName = "cx16.${origtarget.register!!.name.lowercase()}", origAstTarget = origtarget.origAstTarget) } else origtarget } @@ -330,135 +330,229 @@ internal class AssignmentAsmGen(private val program: Program, if(!expr.inferType(program).isInteger) return false - if(expr.operator!="+" && expr.operator!="-") - return false - - val dt = expr.inferType(program).getOrElse { throw AssemblyError("invalid dt") } - val left = expr.left - val right = expr.right - if(dt in ByteDatatypes) { - when (right) { - is IdentifierReference -> { - assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) - val symname = asmgen.asmVariableName(right) - if(expr.operator=="+") - asmgen.out(" clc | adc $symname") - else - asmgen.out(" sec | sbc $symname") - assignRegisterByte(assign.target, CpuRegister.A) - return true + if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) { + if(expr.left.inferType(program).isBytes && expr.right.inferType(program).isBytes && + expr.left.isSimple && expr.right.isSimple) { + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.saveRegisterStack(CpuRegister.A, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine) + asmgen.restoreRegisterStack(CpuRegister.A, false) + when(expr.operator) { + "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1") + "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1") + "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_B1") + else -> throw AssemblyError("invalid operator") } - is NumericLiteral -> { - assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) - if(expr.operator=="+") - asmgen.out(" clc | adc #${right.number.toHex()}") - else - asmgen.out(" sec | sbc #${right.number.toHex()}") - assignRegisterByte(assign.target, CpuRegister.A) - return true - } - else -> return false + assignRegisterByte(assign.target, CpuRegister.A) + return true } - } else if(dt in WordDatatypes) { - when (right) { - is AddressOf -> { - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - val symbol = asmgen.asmVariableName(right.identifier) - if(expr.operator=="+") - asmgen.out(""" - clc - adc #<$symbol - pha - tya - adc #>$symbol - tay - pla""") - else - asmgen.out(""" - sec - sbc #<$symbol - pha - tya - sbc #>$symbol - tay - pla""") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true + if(expr.left.inferType(program).isWords && expr.right.inferType(program).isWords && + expr.left.isSimple && expr.right.isSimple) { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) + asmgen.saveRegisterStack(CpuRegister.A, false) + asmgen.saveRegisterStack(CpuRegister.Y, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSubroutine) + when(expr.operator) { + "&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1") + "|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1") + "^", "xor" -> asmgen.out(" pla | eor P8ZP_SCRATCH_W1+1 | tay | pla | eor P8ZP_SCRATCH_W1") + else -> throw AssemblyError("invalid operator") } - is IdentifierReference -> { - val symname = asmgen.asmVariableName(right) - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - if(expr.operator=="+") - asmgen.out(""" - clc - adc $symname - pha - tya - adc $symname+1 - tay - pla""") - else - asmgen.out(""" - sec - sbc $symname - pha - tya - sbc $symname+1 - tay - pla""") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } + return false + } + + if(expr.operator == "==" || expr.operator == "!=") { + // expression datatype is BOOL (ubyte) but operands can be anything + if(expr.left.inferType(program).isBytes && expr.right.inferType(program).isBytes && + expr.left.isSimple && expr.right.isSimple) { + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.saveRegisterStack(CpuRegister.A, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine) + asmgen.restoreRegisterStack(CpuRegister.A, false) + if(expr.operator=="==") { + asmgen.out(""" + cmp P8ZP_SCRATCH_B1 + bne + + lda #1 + bne ++ ++ lda #0 ++""") + } else { + asmgen.out(""" + cmp P8ZP_SCRATCH_B1 + beq + + lda #1 + bne ++ ++ lda #0 ++""") } - is NumericLiteral -> { - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - if(expr.operator=="+") { - asmgen.out(""" - clc - adc #<${right.number.toHex()} - pha - tya - adc #>${right.number.toHex()} - tay - pla""") - } else if(expr.operator=="-") { - asmgen.out(""" - sec - sbc #<${right.number.toHex()} - pha - tya - sbc #>${right.number.toHex()} - tay - pla""") + assignRegisterByte(assign.target, CpuRegister.A) + return true + } else if(expr.left.inferType(program).isWords && expr.right.inferType(program).isWords && + expr.left.isSimple && expr.right.isSimple) { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) + asmgen.saveRegisterStack(CpuRegister.A, false) + asmgen.saveRegisterStack(CpuRegister.Y, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSubroutine) + asmgen.restoreRegisterStack(CpuRegister.Y, false) + asmgen.restoreRegisterStack(CpuRegister.A, false) + if(expr.operator=="==") { + asmgen.out(""" + cmp P8ZP_SCRATCH_W1 + bne + + cpy P8ZP_SCRATCH_W1+1 + bne + + lda #1 + bne ++ ++ lda #0 ++""") + } else { + asmgen.out(""" + cmp P8ZP_SCRATCH_W1 + bne + + cpy P8ZP_SCRATCH_W1+1 + bne + + lda #0 + bne ++ ++ lda #1 ++""") + } + assignRegisterByte(assign.target, CpuRegister.A) + return true + } + return false + } + else if(expr.operator=="+" || expr.operator=="-") { + val dt = expr.inferType(program).getOrElse { throw AssemblyError("invalid dt") } + val left = expr.left + val right = expr.right + if(dt in ByteDatatypes) { + when (right) { + is IdentifierReference -> { + assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) + val symname = asmgen.asmVariableName(right) + if(expr.operator=="+") + asmgen.out(" clc | adc $symname") + else + asmgen.out(" sec | sbc $symname") + assignRegisterByte(assign.target, CpuRegister.A) + return true } - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true + is NumericLiteral -> { + assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) + if(expr.operator=="+") + asmgen.out(" clc | adc #${right.number.toHex()}") + else + asmgen.out(" sec | sbc #${right.number.toHex()}") + assignRegisterByte(assign.target, CpuRegister.A) + return true + } + else -> return false } - is TypecastExpression -> { - val castedValue = right.expression - if(right.type in WordDatatypes && castedValue.inferType(program).isBytes) { - if(castedValue is IdentifierReference) { - val castedSymname = asmgen.asmVariableName(castedValue) - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - if(expr.operator=="+") - asmgen.out(""" - clc - adc $castedSymname - bcc + - iny -+""") - else - asmgen.out(""" - sec - sbc $castedSymname - bcs + - dey -+""") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true + } else if(dt in WordDatatypes) { + when (right) { + is AddressOf -> { + assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + val symbol = asmgen.asmVariableName(right.identifier) + if(expr.operator=="+") + asmgen.out(""" + clc + adc #<$symbol + pha + tya + adc #>$symbol + tay + pla""") + else + asmgen.out(""" + sec + sbc #<$symbol + pha + tya + sbc #>$symbol + tay + pla""") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } + is IdentifierReference -> { + val symname = asmgen.asmVariableName(right) + assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + if(expr.operator=="+") + asmgen.out(""" + clc + adc $symname + pha + tya + adc $symname+1 + tay + pla""") + else + asmgen.out(""" + sec + sbc $symname + pha + tya + sbc $symname+1 + tay + pla""") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } + is NumericLiteral -> { + assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + if(expr.operator=="+") { + asmgen.out(""" + clc + adc #<${right.number.toHex()} + pha + tya + adc #>${right.number.toHex()} + tay + pla""") + } else if(expr.operator=="-") { + asmgen.out(""" + sec + sbc #<${right.number.toHex()} + pha + tya + sbc #>${right.number.toHex()} + tay + pla""") + } + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } + is TypecastExpression -> { + val castedValue = right.expression + if(right.type in WordDatatypes && castedValue.inferType(program).isBytes) { + if(castedValue is IdentifierReference) { + val castedSymname = asmgen.asmVariableName(castedValue) + assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + if(expr.operator=="+") + asmgen.out(""" + clc + adc $castedSymname + bcc + + iny + +""") + else + asmgen.out(""" + sec + sbc $castedSymname + bcs + + dey + +""") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } } } + else -> return false } - else -> return false } } return false @@ -561,7 +655,7 @@ internal class AssignmentAsmGen(private val program: Program, val varname = asmgen.asmVariableName(containment.iterable as IdentifierReference) assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) asmgen.out(" ldy #${stringVal.value.length}") asmgen.out(" jsr prog8_lib.containment_bytearray") @@ -580,14 +674,14 @@ internal class AssignmentAsmGen(private val program: Program, in ByteDatatypes -> { assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) asmgen.out(" ldy #${arrayVal.value.size}") asmgen.out(" jsr prog8_lib.containment_bytearray") } in WordDatatypes -> { assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt.getOr(DataType.UNDEFINED), containment.definingSubroutine) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname) asmgen.out(" ldy #${arrayVal.value.size}") asmgen.out(" jsr prog8_lib.containment_wordarray") } @@ -604,7 +698,7 @@ internal class AssignmentAsmGen(private val program: Program, // use subroutine assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) val stringVal = variable.value as StringLiteral asmgen.out(" ldy #${stringVal.value.length}") @@ -618,7 +712,7 @@ internal class AssignmentAsmGen(private val program: Program, val arrayVal = variable.value as ArrayLiteral assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) asmgen.out(" ldy #${arrayVal.value.size}") asmgen.out(" jsr prog8_lib.containment_bytearray") @@ -627,7 +721,7 @@ internal class AssignmentAsmGen(private val program: Program, DataType.ARRAY_W, DataType.ARRAY_UW -> { val arrayVal = variable.value as ArrayLiteral assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt.getOr(DataType.UNDEFINED), containment.definingSubroutine) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname) asmgen.out(" ldy #${arrayVal.value.size}") asmgen.out(" jsr prog8_lib.containment_wordarray") return @@ -2579,7 +2673,7 @@ internal class AssignmentAsmGen(private val program: Program, internal fun assignExpressionToRegister(expr: Expression, register: RegisterOrPair, signed: Boolean) { val src = AsmAssignSource.fromAstSource(expr, program, asmgen) - val tgt = AsmAssignTarget.fromRegisters(register, signed, null, program, asmgen) + val tgt = AsmAssignTarget.fromRegisters(register, signed, null, asmgen) val assign = AsmAssignment(src, tgt, false, program.memsizer, expr.position) translateNormalAssignment(assign) } @@ -2589,14 +2683,14 @@ internal class AssignmentAsmGen(private val program: Program, throw AssemblyError("can't directly assign a FLOAT expression to an integer variable $expr") } else { val src = AsmAssignSource.fromAstSource(expr, program, asmgen) - val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, scope, variableAsmName = asmVarName) + val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, scope, variableAsmName = asmVarName) val assign = AsmAssignment(src, tgt, false, program.memsizer, expr.position) translateNormalAssignment(assign) } } internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, signed: Boolean) { - val tgt = AsmAssignTarget.fromRegisters(register, signed, null, program, asmgen) + val tgt = AsmAssignTarget.fromRegisters(register, signed, null, asmgen) val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, tgt.datatype, variableAsmName = asmVarName) val assign = AsmAssignment(src, tgt, false, program.memsizer, Position.DUMMY) translateNormalAssignment(assign) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index e9e524209..251da837e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -236,7 +236,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } else -> { // TODO use some other evaluation here; don't use the estack to transfer the address to read/write from - asmgen.assignExpressionTo(memory.addressExpression, AsmAssignTarget(TargetStorageKind.STACK, program, asmgen, DataType.UWORD, memory.definingSubroutine)) + asmgen.assignExpressionTo(memory.addressExpression, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingSubroutine)) asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1") when { valueLv != null -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, valueLv.toInt()) @@ -305,7 +305,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, AsmAssignTarget.fromRegisters( RegisterOrPair.A, target.datatype == DataType.BYTE, null, - program, asmgen ) val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) @@ -317,7 +316,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, AsmAssignTarget.fromRegisters( RegisterOrPair.AY, target.datatype == DataType.WORD, null, - program, asmgen ) val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) @@ -329,7 +327,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, AsmAssignTarget.fromRegisters( RegisterOrPair.FAC1, true, null, - program, asmgen ) val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 1304b194f..3d2c81fe2 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- can we optimize logical expresions such as if input_size and command_line[0]!=159 to not use stack eval anymore? - ... diff --git a/examples/test.p8 b/examples/test.p8 index 4d5aa2c8e..5179c1ae9 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,26 +1,41 @@ %import textio -%import string -%zeropage kernalsafe +%zeropage basicsafe main { sub start() { - cx16.r0 = $ea31 - cx16.r15 = $ff99 - str name = "irmen" + bool aa = true + ubyte[] bb = [%0000, %1111] + uword w1 = %1000000000000001 + uword w2 = %0000000000000010 - txt.print_uwhex(cx16.r0, true) + if aa and w1 | w2 + txt.print("ok") + else + txt.print("fail") txt.spc() - txt.print_uwhex(cx16.r15, true) - txt.nl() - cx16.r7 = &name - txt.chrout(cx16.r7[0]) - txt.chrout(cx16.r7[1]) - txt.chrout(cx16.r7[2]) - txt.chrout(cx16.r7[3]) - txt.chrout(cx16.r7[4]) - txt.nl() - repeat { - } + if aa and w1 & w2 + txt.print("fail") + else + txt.print("ok") + txt.spc() + + if aa and bb[0] | %0100 + txt.print("ok") + else + txt.print("fail") + txt.spc() + + if aa and bb[0] & %0100 + txt.print("fail") + else + txt.print("ok") + txt.spc() + + aa = aa and bb[0] | %0100 + txt.print_ub(aa) + txt.spc() + aa = aa and bb[0] & %0100 + txt.print_ub(aa) } }