diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index c29666a0b..249dc8d5e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -429,35 +429,101 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } - if(expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) { - if(assignOptimizedComparisonBytes(expr, assign)) - return true - } else if(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { - if(assignOptimizedComparisonWords(expr, assign)) + if(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + if(assignOptimizedComparisonWords(expr, assign)) // TODO remove this! return true } - val origTarget = assign.target.origAstTarget - if(origTarget!=null) { - assignConstantByte(assign.target, 0) - val assignTrue = PtNodeGroup() - val assignment = PtAssignment(assign.position) - assignment.add(origTarget) - assignment.add(PtNumber.fromBoolean(true, assign.position)) - assignTrue.add(assignment) - val assignFalse = PtNodeGroup() + // b = v > 99 --> b=false , if v>99 b=true + val targetReg=assign.target.register + if(targetReg!=null) { + // a register as target should be handled slightly differently to avoid overwriting the value + val ifPart = PtNodeGroup() + val elsePart = PtNodeGroup() + val reg = when(targetReg) { + RegisterOrPair.A -> "a" + RegisterOrPair.X -> "x" + RegisterOrPair.Y -> "y" + else -> TODO("comparison to word register") + } + val assignTrue = PtInlineAssembly(" ld${reg} #1", false, assign.target.position) + val assignFalse = PtInlineAssembly(" ld${reg} #0", false, assign.target.position) + ifPart.add(assignTrue) + elsePart.add(assignFalse) val ifelse = PtIfElse(assign.position) val exprClone = PtBinaryExpression(expr.operator, expr.type, expr.position) expr.children.forEach { exprClone.children.add(it) } // doesn't seem to need a deep clone ifelse.add(exprClone) - ifelse.add(assignTrue) - ifelse.add(assignFalse) + ifelse.add(ifPart) + ifelse.add(elsePart) ifelse.parent = expr.parent asmgen.translate(ifelse) return true } - - return false + val target = assign.target.origAstTarget + assignConstantByte(assign.target, 0) + val ifPart = PtNodeGroup() + val assignTrue: PtNode + if(target!=null) { + // set target to true + assignTrue = PtAssignment(assign.position) + assignTrue.add(target) + assignTrue.add(PtNumber.fromBoolean(true, assign.position)) + } else { + require(assign.target.datatype in ByteDatatypes) + when(assign.target.kind) { + TargetStorageKind.VARIABLE -> { + if(assign.target.datatype in WordDatatypes) { + assignTrue = if(asmgen.isTargetCpu(CpuType.CPU65c02)) { + PtInlineAssembly(""" + lda #1 + sta ${assign.target.asmVarname} + stz ${assign.target.asmVarname}+1""", false, assign.target.position) + } else { + PtInlineAssembly(""" + lda #1 + sta ${assign.target.asmVarname} + lda #0 + sta ${assign.target.asmVarname}+1""", false, assign.target.position) + } + } else { + assignTrue = PtInlineAssembly(" lda #1\n sta ${assign.target.asmVarname}", false, assign.target.position) + } + } + TargetStorageKind.MEMORY -> { + val tgt = PtAssignTarget(assign.target.position) + val targetmem = assign.target.memory!! + val mem = PtMemoryByte(targetmem.position) + mem.add(targetmem.address) + tgt.add(mem) + assignTrue = PtAssignment(assign.position) + assignTrue.add(tgt) + assignTrue.add(PtNumber.fromBoolean(true, assign.position)) + } + TargetStorageKind.ARRAY -> { + val tgt = PtAssignTarget(assign.target.position) + val targetarray = assign.target.array!! + val array = PtArrayIndexer(assign.target.datatype, targetarray.position) + array.add(targetarray.variable) + array.add(targetarray.index) + tgt.add(array) + assignTrue = PtAssignment(assign.position) + assignTrue.add(tgt) + assignTrue.add(PtNumber.fromBoolean(true, assign.position)) + } + TargetStorageKind.REGISTER -> { /* handled earlier */ return true } + } + } + ifPart.add(assignTrue) + val ifelse = PtIfElse(assign.position) + val exprClone = PtBinaryExpression(expr.operator, expr.type, expr.position) + expr.children.forEach { exprClone.children.add(it) } // doesn't seem to need a deep clone + ifelse.add(exprClone) + ifelse.add(ifPart) + ifelse.add(PtNodeGroup()) + ifelse.parent = expr.parent + asmgen.translate(ifelse) + return true } private fun directIntoY(expr: PtExpression): Boolean { @@ -1140,386 +1206,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, return false } - private fun assignOptimizedComparisonBytes(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { - val signed = expr.left.type == DataType.BYTE || expr.right.type == DataType.BYTE - when(expr.operator) { - "==" -> byteEquals(expr) - "!=" -> byteNotEquals(expr) - "<" -> byteLess(expr, signed) - "<=" -> byteLessEquals(expr, signed) - ">" -> byteGreater(expr, signed) - ">=" -> byteGreaterEquals(expr, signed) - else -> return false - } - - assignRegisterByte(assign.target, CpuRegister.A, false, true) - return true - } - - private fun byteEquals(expr: PtBinaryExpression) { - when (expr.right) { - is PtNumber -> { - val number = (expr.right as PtNumber).number.toInt() - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A) - asmgen.out(""" - cmp #$number - beq + - lda #0 - beq ++ -+ lda #1 -+""") - } - is PtIdentifier -> { - val varname = (expr.right as PtIdentifier).name - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A) - asmgen.out(""" - cmp $varname - beq + - lda #0 - beq ++ -+ lda #1 -+""") - } - else -> { - asmgen.assignByteOperandsToAAndVar(expr.right, expr.left, "P8ZP_SCRATCH_B1") - asmgen.out(""" - cmp P8ZP_SCRATCH_B1 - beq + - lda #0 - beq ++ -+ lda #1 -+""") - } - } - } - - private fun byteNotEquals(expr: PtBinaryExpression) { - when(expr.right) { - is PtNumber -> { - val number = (expr.right as PtNumber).number.toInt() - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A) - asmgen.out(""" - cmp #$number - bne + - lda #0 - beq ++ -+ lda #1 -+""") - } - is PtIdentifier -> { - val varname = (expr.right as PtIdentifier).name - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A) - asmgen.out(""" - cmp $varname - bne + - lda #0 - beq ++ -+ lda #1 -+""") - } - else -> { - asmgen.assignByteOperandsToAAndVar(expr.right, expr.left, "P8ZP_SCRATCH_B1") - asmgen.out(""" - cmp P8ZP_SCRATCH_B1 - bne + - lda #0 - beq ++ -+ lda #1 -+""") - } - } - } - - private fun byteLess(expr: PtBinaryExpression, signed: Boolean) { - // note: this is the inverse of byteGreaterEqual - when(expr.right) { - is PtNumber -> { - val number = (expr.right as PtNumber).number.toInt() - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(signed) { - asmgen.out(""" - sec - sbc #$number - bvs + - eor #$80 -+ asl a - rol a - and #1 - eor #1""") - } - else - asmgen.out(""" - cmp #$number - rol a - and #1 - eor #1""") - } - is PtIdentifier -> { - val varname = (expr.right as PtIdentifier).name - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(signed) { - asmgen.out(""" - sec - sbc $varname - bvs + - eor #$80 -+ asl a - rol a - and #1 - eor #1""") - } - else - asmgen.out(""" - cmp $varname - rol a - and #1 - eor #1""") - } - else -> { - // note: left and right operands get reversed here to reduce code size - asmgen.assignByteOperandsToAAndVar(expr.right, expr.left, "P8ZP_SCRATCH_B1") - if(signed) - asmgen.out(""" - clc - sbc P8ZP_SCRATCH_B1 - bvs + - eor #$80 -+ asl a - rol a - and #1""") - else - asmgen.out(""" - cmp P8ZP_SCRATCH_B1 - bcc + - beq + - lda #1 - bne ++ -+ lda #0 -+""") - } - } - } - - private fun byteLessEquals(expr: PtBinaryExpression, signed: Boolean) { - // note: this is the inverse of byteGreater - when(expr.right) { - is PtNumber -> { - val number = (expr.right as PtNumber).number.toInt() - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(signed) - asmgen.out(""" - sec - sbc #$number - bvc + - eor #$80 -+ bmi + - beq + - lda #0 - beq ++ -+ lda #1 -+""") - else - asmgen.out(""" - cmp #$number - bcc + - beq + - lda #0 - beq ++ -+ lda #1 -+""") - } - is PtIdentifier -> { - val varname = (expr.right as PtIdentifier).name - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(signed) - asmgen.out(""" - sec - sbc $varname - bvc + - eor #$80 -+ bmi + - beq + - lda #0 - beq ++ -+ lda #1 -+""") - else - asmgen.out(""" - cmp $varname - bcc + - beq + - lda #0 - beq ++ -+ lda #1 -+""") - } - else -> { - // note: left and right operands get reversed here to reduce code size - asmgen.assignByteOperandsToAAndVar(expr.right, expr.left, "P8ZP_SCRATCH_B1") - if(signed) - asmgen.out(""" - sec - sbc P8ZP_SCRATCH_B1 - bvc + - eor #$80 -+ bmi + - lda #1 - bne ++ -+ lda #0 -+""") - else - asmgen.out(""" - cmp P8ZP_SCRATCH_B1 - lda #0 - rol a""") - } - } - } - - private fun byteGreater(expr: PtBinaryExpression, signed: Boolean) { - // note: this is the inverse of byteLessEqual - when(expr.right) { - is PtNumber -> { - val number = (expr.right as PtNumber).number.toInt() - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(signed) - asmgen.out(""" - sec - sbc #$number - beq +++ - bvc + - eor #$80 -+ bmi + - lda #1 - bne ++ -+ lda #0 -+""") - else - asmgen.out(""" - cmp #$number - bcc + - beq + - lda #1 - bne ++ -+ lda #0 -+""") - } - is PtIdentifier -> { - val varname = (expr.right as PtIdentifier).name - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(signed) - asmgen.out(""" - sec - sbc $varname - beq +++ - bvc + - eor #$80 -+ bmi + - lda #1 - bne ++ -+ lda #0 -+""") - else - asmgen.out(""" - cmp $varname - bcc + - beq + - lda #1 - bne ++ -+ lda #0 -+""") - } - else -> { - // note: left and right operands get reversed here to reduce code size - asmgen.assignByteOperandsToAAndVar(expr.right, expr.left, "P8ZP_SCRATCH_B1") - if(signed) - asmgen.out(""" - sec - sbc P8ZP_SCRATCH_B1 - bvc + - eor #$80 -+ bmi + - lda #0 - beq ++ -+ lda #1 -+""") - else - asmgen.out(""" - cmp P8ZP_SCRATCH_B1 - lda #0 - rol a - eor #1""") - } - } - } - - private fun byteGreaterEquals(expr: PtBinaryExpression, signed: Boolean) { - // note: this is the inverse of byteLess - when(expr.right) { - is PtNumber -> { - val number = (expr.right as PtNumber).number.toInt() - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(signed) { - asmgen.out(""" - sec - sbc #$number - bvs + - eor #$80 -+ asl a - rol a - and #1""") - } - else - asmgen.out(""" - cmp #$number - rol a - and #1""") - } - is PtIdentifier -> { - val varname = (expr.right as PtIdentifier).name - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(signed) { - asmgen.out(""" - sec - sbc $varname - bvs + - eor #$80 -+ asl a - rol a - and #1""") - } - else - asmgen.out(""" - cmp $varname - rol a - and #1""") - } - else -> { - // note: left and right operands get reversed here to reduce code size - asmgen.assignByteOperandsToAAndVar(expr.right, expr.left, "P8ZP_SCRATCH_B1") - if(signed) - asmgen.out(""" - clc - sbc P8ZP_SCRATCH_B1 - bvs + - eor #$80 -+ asl a - rol a - and #1 - eor #1""") - else - asmgen.out(""" - cmp P8ZP_SCRATCH_B1 - bcc + - beq + - lda #0 - beq ++ -+ lda #1 -+""") - } - } - } - private fun assignOptimizedComparisonWords(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { val signed = expr.left.type == DataType.WORD || expr.right.type == DataType.WORD diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 513c3bfc2..64bb05b38 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,6 +1,12 @@ TODO ==== +textelite is larger + + +optimize assignOptimizedComparisonWords for when comparing to simple things like number and identifier. (get rid of it completely by just rewriting everything into an if-else statement?) +optimize optimizedPlusMinExpr for when comparing to simple things like number and identifier. + replace Takes by Http4k in httpCompilerService project. https://github.com/http4k/examples/blob/master/hello-world/README.md ... diff --git a/examples/test.p8 b/examples/test.p8 index de407d781..762183450 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,133 +1,20 @@ %import textio -%zeropage dontuse %option no_sysinit +%zeropage basicsafe main { sub start() { - uword @shared pointer - cx16.r0L = 10 - pointer = &label2 - if cx16.r0L!=0 - goto pointer - -label1: - txt.print("fail\n") - return - -label2: - txt.print("indirect jump ok\n") - return + ubyte @shared xx = 16 + ubyte @shared yy = 20 + txt.print_ub(xx>79 or yy > 49) + ; if xx>79 or yy > 49 { +; if xx>79 or yy > 49 { +; txt.print("no\n") +; } +; else { +; txt.print("yes\n") +; } } } - - - -;%import textio -;%import floats -;%zeropage dontuse -;%option no_sysinit -; -;main { -; sub start() { -; test_bool() -;; test_byte() -;; test_ubyte() -;; test_word() -;; test_uword() -;; test_float() -; } -; -; /* -; tests: -; - if with only a single goto, direct -; - if with only a single indirect goto -; - if without an else block -; - if with both if and else blocks -; carthesian product with: -; - comparison with const zero -; - comparison with const values -; - comparison with variable -; - comparison with array -; - comparison with expression -; */ -; -; sub fail(uword test) { -; txt.print("failed ") -; txt.print_uw(test) -; txt.nl() -; } -; -; sub test_bool() { -; bool @shared var1, var2 -; uword success = 0 -; -; single_goto() -; single_goto_indirect() -; no_else() -; ifelse() -; -; sub single_goto() { -; txt.print("bool single_goto\n") -;test1: -; var1 = false -; if var1 -; goto lbl1 -; success++ -; goto test2 -;lbl1: -; fail(1) -; -;test2: -; var1 = true -; if var1 -; goto lbl2 -; fail(1) -; goto test3 -;lbl2: success++ -; -;test3: -; if success==2 -; txt.print(" ok\n") -; else -; txt.print(" failed\n") -; } -; -; sub single_goto_indirect() { -; uword pointer -; txt.print("bool single_goto_indirect\n") -;test1: -; var1 = false -; pointer = &lbl1 -; if var1 -; goto pointer -; success++ -; goto test2 -;lbl1: -; fail(1) -; -;test2: -; var1 = true -; pointer = &lbl2 -; if var1 -; goto pointer -; fail(1) -; goto test3 -;lbl2: success++ -; -;test3: -; if success==2 -; txt.print(" ok\n") -; else -; txt.print(" failed\n") -; } -; -; sub no_else() { -; } -; -; sub ifelse() { -; } -; } -; -;}