diff --git a/codeAst/src/prog8/code/ast/AstExpressions.kt b/codeAst/src/prog8/code/ast/AstExpressions.kt index 2f3056898..076260dc4 100644 --- a/codeAst/src/prog8/code/ast/AstExpressions.kt +++ b/codeAst/src/prog8/code/ast/AstExpressions.kt @@ -153,6 +153,12 @@ class PtPrefix(val operator: String, type: DataType, position: Position): PtExpr val value: PtExpression get() = children.single() as PtExpression + init { + // note: the "not" operator may no longer occur in the ast; not x should have been replaced with x==0 + if(operator !in setOf("+", "-", "~")) + throw IllegalArgumentException("invalid prefix operator: $operator") + } + override fun printProperties() { print(operator) } diff --git a/codeCore/src/prog8/code/core/Operators.kt b/codeCore/src/prog8/code/core/Operators.kt index ca4e40abb..a706e5045 100644 --- a/codeCore/src/prog8/code/core/Operators.kt +++ b/codeCore/src/prog8/code/core/Operators.kt @@ -3,7 +3,7 @@ package prog8.code.core val AssociativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=") val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=") val AugmentAssignmentOperators = setOf("+", "-", "/", "*", "&", "|", "^", "<<", ">>", "%", "and", "or", "xor") -val LogicalOperators = setOf("and", "or", "xor", "not") +val LogicalOperators = setOf("and", "or", "xor") // not x is replaced with x==0 val BitwiseOperators = setOf("&", "|", "^") fun invertedComparisonOperator(operator: String) = diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt index 6e6a3a360..fea13e17e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt @@ -664,22 +664,6 @@ internal class ExpressionsAsmGen(private val program: Program, else -> throw AssemblyError("weird type") } } - "not" -> { - when(type) { - // if reg==0 -> - /* - lda P8ESTACK_LO+1,x - beq + - lda #1 -+ eor #1 - sta P8ESTACK_LO+1,x - rts - */ - in ByteDatatypes -> asmgen.out(" jsr prog8_lib.not_byte") - in WordDatatypes -> asmgen.out(" jsr prog8_lib.not_word") - else -> throw AssemblyError("weird type") - } - } else -> throw AssemblyError("invalid prefix operator ${expr.operator}") } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 67f203c67..cf0f797cf 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -283,7 +283,6 @@ internal class AssignmentAsmGen(private val program: Program, "+" -> {} "-" -> augmentableAsmGen.inplaceNegate(target, target.datatype) "~" -> augmentableAsmGen.inplaceInvert(target, target.datatype) - "not" -> augmentableAsmGen.inplaceBooleanNot(target, target.datatype) else -> throw AssemblyError("invalid prefix operator") } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index c06f28394..64e5ac1d4 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -28,7 +28,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, "+" -> {} "-" -> inplaceNegate(target, type) "~" -> inplaceInvert(target, type) - "not" -> inplaceBooleanNot(target, type) else -> throw AssemblyError("invalid prefix operator") } } @@ -1800,136 +1799,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - internal fun inplaceBooleanNot(target: AsmAssignTarget, dt: DataType) { - when (dt) { - DataType.UBYTE -> { - when (target.kind) { - TargetStorageKind.VARIABLE -> { - asmgen.out(""" - lda ${target.asmVarname} - beq + - lda #1 -+ eor #1 - sta ${target.asmVarname}""") - } - TargetStorageKind.MEMORY -> { - val mem = target.memory!! - when (mem.addressExpression) { - is NumericLiteral -> { - val addr = (mem.addressExpression as NumericLiteral).number.toHex() - asmgen.out(""" - lda $addr - beq + - lda #1 -+ eor #1 - sta $addr""") - } - is IdentifierReference -> { - val sourceName = asmgen.loadByteFromPointerIntoA(mem.addressExpression as IdentifierReference) - asmgen.out(""" - beq + - lda #1 -+ eor #1""") - asmgen.storeAIntoZpPointerVar(sourceName) - } - else -> { - asmgen.assignExpressionToVariable(mem.addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD, target.scope) - asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2") - asmgen.out(""" - beq + - lda #1 -+ eor #1""") - asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2") - } - } - } - TargetStorageKind.REGISTER -> { - when(target.register!!) { - RegisterOrPair.A -> asmgen.out(""" - cmp #0 - beq + - lda #1 -+ eor #1""") - RegisterOrPair.X -> asmgen.out(""" - txa - beq + - lda #1 -+ eor #1 - tax""") - RegisterOrPair.Y -> asmgen.out(""" - tya - beq + - lda #1 -+ eor #1 - tay""") - else -> throw AssemblyError("invalid reg dt for byte not") - } - } - TargetStorageKind.STACK -> TODO("no asm gen for byte stack not") - else -> throw AssemblyError("no asm gen for in-place not of ubyte ${target.kind}") - } - } - DataType.UWORD -> { - when (target.kind) { - TargetStorageKind.VARIABLE -> { - asmgen.out(""" - lda ${target.asmVarname} - ora ${target.asmVarname}+1 - beq + - lda #1 -+ eor #1 - sta ${target.asmVarname} - lsr a - sta ${target.asmVarname}+1""") - } - TargetStorageKind.REGISTER -> { - when(target.register!!) { - RegisterOrPair.AX -> { - asmgen.out(""" - stx P8ZP_SCRATCH_REG - ora P8ZP_SCRATCH_REG - beq + - lda #0 - tax - beq ++ - + lda #1 - +""") - } - RegisterOrPair.AY -> { - asmgen.out(""" - sty P8ZP_SCRATCH_REG - ora P8ZP_SCRATCH_REG - beq + - lda #0 - tay - beq ++ - + lda #1 - +""") - } - RegisterOrPair.XY -> { - asmgen.out(""" - stx P8ZP_SCRATCH_REG - tya - ora P8ZP_SCRATCH_REG - beq + - ldy #0 - ldx #0 - beq ++ - + ldx #1 - +""") - } - in Cx16VirtualRegisters -> throw AssemblyError("cx16 virtual regs should be variables, not real registers") - else -> throw AssemblyError("invalid reg dt for word not") - } - } - TargetStorageKind.STACK -> TODO("no asm gen for word stack not") - else -> throw AssemblyError("no asm gen for in-place not of uword for ${target.kind}") - } - } - else -> throw AssemblyError("boolean-not of invalid type") - } - } - internal fun inplaceInvert(target: AsmAssignTarget, dt: DataType) { when (dt) { DataType.UBYTE -> { diff --git a/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt index 62929674d..9e0dffba9 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt @@ -110,9 +110,6 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask) code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = address) } - "not" -> { - code += VmCodeInstruction(Opcode.NOTM, vmDt, value = address) - } else -> throw AssemblyError("weird prefix operator") } return code diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index 8f47fb3f0..dca6b41b4 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -154,9 +154,6 @@ internal class ExpressionGen(private val codeGen: CodeGen) { code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask) code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=regMask) } - "not" -> { - code += VmCodeInstruction(Opcode.NOT, vmDt, reg1=resultRegister) - } else -> throw AssemblyError("weird prefix operator") } return code @@ -391,13 +388,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) { comparisonCall.children.add(binExpr.left) comparisonCall.children.add(binExpr.right) code += translate(comparisonCall, resultRegister, -1) - if(notEquals) { - val maskReg = codeGen.vmRegisters.nextFree() - code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=maskReg, value=1) - code += VmCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=maskReg) - } else { - code += VmCodeInstruction(Opcode.NOT, vmDt, reg1=resultRegister) - } + if(!notEquals) + code += VmCodeInstruction(Opcode.INV, vmDt, reg1=resultRegister) + val maskReg = codeGen.vmRegisters.nextFree() + code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=maskReg, value=1) + code += VmCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=maskReg) } else { val rightResultReg = codeGen.vmRegisters.nextFree() code += translateExpression(binExpr.left, resultRegister, -1) diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 014caa7bd..b72d03401 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -80,11 +80,6 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() { } else -> throw ExpressionError("can only take bitwise inversion of int", subexpr.position) } - "not" -> { - listOf(IAstModification.ReplaceNode(expr, - NumericLiteral.fromBoolean(subexpr.number == 0.0, subexpr.position), - parent)) - } else -> throw ExpressionError(expr.operator, subexpr.position) } } diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index ef85a5824..0cbccd893 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -108,7 +108,7 @@ class StatementOptimizer(private val program: Program, // empty true part? switch with the else part if(ifElse.truepart.isEmpty() && ifElse.elsepart.isNotEmpty()) { - val invertedCondition = PrefixExpression("not", ifElse.condition, ifElse.condition.position) + val invertedCondition = BinaryExpression(ifElse.condition, "==", NumericLiteral.fromBoolean(false, ifElse.condition.position), ifElse.condition.position) val emptyscope = AnonymousScope(mutableListOf(), ifElse.elsepart.position) val truepart = AnonymousScope(ifElse.elsepart.statements, ifElse.truepart.position) return listOf( diff --git a/compiler/res/prog8lib/prog8_lib.asm b/compiler/res/prog8lib/prog8_lib.asm index 03c3599a8..1cf3d002c 100644 --- a/compiler/res/prog8lib/prog8_lib.asm +++ b/compiler/res/prog8lib/prog8_lib.asm @@ -58,27 +58,6 @@ inv_word .proc rts .pend -not_byte .proc - lda P8ESTACK_LO+1,x - beq + - lda #1 -+ eor #1 - sta P8ESTACK_LO+1,x - rts - .pend - -not_word .proc - lda P8ESTACK_LO + 1,x - ora P8ESTACK_HI + 1,x - beq + - lda #1 -+ eor #1 - sta P8ESTACK_LO + 1,x - lsr a - sta P8ESTACK_HI + 1,x - rts - .pend - bitand_b .proc ; -- bitwise and (of 2 bytes) lda P8ESTACK_LO+2,x diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 137adb6f2..7bee287a1 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -823,10 +823,6 @@ internal class AstChecker(private val program: Program, errors.err("can only take negative of a signed number type", expr.position) } } - else if(expr.operator == "not") { - if(dt !in IntegerDatatypes) - errors.err("can only use boolean not on integer types", expr.position) - } else if(expr.operator == "~") { if(dt !in IntegerDatatypes) errors.err("can only use bitwise invert on integer types", expr.position) diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index cf525a36c..f1c008a45 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -3,6 +3,7 @@ package prog8.compiler.astprocessing import prog8.ast.IFunctionCall import prog8.ast.Node import prog8.ast.Program +import prog8.ast.base.FatalAstException import prog8.ast.base.SyntaxError import prog8.ast.expressions.* import prog8.ast.statements.* @@ -116,7 +117,8 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp override fun before(expr: PrefixExpression, parent: Node): Iterable { if(expr.operator == "not") { // not(x) --> x==0 - val dt = expr.expression.inferType(program).getOr(DataType.UNDEFINED) + // this means that "not" will never occur anywhere again in the ast + val dt = expr.expression.inferType(program).getOr(DataType.UBYTE) val replacement = BinaryExpression(expr.expression, "==", NumericLiteral(dt,0.0, expr.position), expr.position) return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent)) } diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt index 8185bf3c8..fba3c293f 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt @@ -169,18 +169,6 @@ internal class BeforeAsmAstChanger(val program: Program, } override fun after(ifElse: IfElse, parent: Node): Iterable { - val prefixExpr = ifElse.condition as? PrefixExpression - if(prefixExpr!=null && prefixExpr.operator=="not") { - // if not x -> if x==0 - val booleanExpr = BinaryExpression( - prefixExpr.expression, - "==", - NumericLiteral.optimalInteger(0, ifElse.condition.position), - ifElse.condition.position - ) - return listOf(IAstModification.ReplaceNode(ifElse.condition, booleanExpr, ifElse)) - } - val binExpr = ifElse.condition as? BinaryExpression if(binExpr==null || binExpr.operator !in ComparisonOperators) { // if x -> if x!=0, if x+5 -> if x+5 != 0 diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 00014eced..3796f8b77 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -1,10 +1,7 @@ package prog8.compiler.astprocessing import prog8.ast.* -import prog8.ast.expressions.DirectMemoryRead -import prog8.ast.expressions.FunctionCallExpression -import prog8.ast.expressions.IdentifierReference -import prog8.ast.expressions.PrefixExpression +import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification @@ -58,16 +55,16 @@ do { STUFF } until CONDITION ===> _loop: STUFF -if not CONDITION +if CONDITION==0 goto _loop */ val pos = untilLoop.position val loopLabel = program.makeLabel("untilloop", pos) - val notCondition = PrefixExpression("not", untilLoop.condition, pos) + val equalsZero = BinaryExpression(untilLoop.condition, "==", NumericLiteral.fromBoolean(false, pos), pos) val replacement = AnonymousScope(mutableListOf( loopLabel, untilLoop.body, - IfElse(notCondition, + IfElse(equalsZero, AnonymousScope(mutableListOf(program.jumpLabel(loopLabel)), pos), AnonymousScope(mutableListOf(), pos), pos) @@ -80,7 +77,7 @@ if not CONDITION while CONDITION { STUFF } ==> _whileloop: - if NOT CONDITION goto _after + if CONDITION==0 goto _after STUFF goto _whileloop _after: @@ -88,10 +85,10 @@ _after: val pos = whileLoop.position val loopLabel = program.makeLabel("whileloop", pos) val afterLabel = program.makeLabel("afterwhile", pos) - val notCondition = PrefixExpression("not", whileLoop.condition, pos) + val equalsZero = BinaryExpression(whileLoop.condition, "==", NumericLiteral.fromBoolean(false, pos), pos) val replacement = AnonymousScope(mutableListOf( loopLabel, - IfElse(notCondition, + IfElse(equalsZero, AnonymousScope(mutableListOf(program.jumpLabel(afterLabel)), pos), AnonymousScope(mutableListOf(), pos), pos), diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index 0d302eb56..0e7cfb34c 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -102,19 +102,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val return noModifications } - override fun after(expr: PrefixExpression, parent: Node): Iterable { - if(expr.operator=="not") { - val logical = parent as? BinaryExpression - if(logical!=null && logical.operator in LogicalOperators) { - // not x as operand in a logical expression --> cast it to ubyte - // TODO is this cast really necessary or does boolean() wrapping take care of it? - val cast = TypecastExpression(expr, DataType.UBYTE, true, expr.position) - return listOf(IAstModification.ReplaceNode(expr, cast, parent)) - } - } - return noModifications - } - override fun after(assignment: Assignment, parent: Node): Iterable { // see if a typecast is needed to convert the value's type into the proper target type val valueItype = assignment.value.inferType(program) diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index 0d5f088ed..f4eca15ac 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -71,22 +71,6 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, // +X --> X return listOf(IAstModification.ReplaceNode(expr, expr.expression, parent)) } - if(expr.operator=="not") { - val nestedPrefix = expr.expression as? PrefixExpression - if(nestedPrefix!=null && nestedPrefix.operator=="not") { - // NOT NOT X --> X - return listOf(IAstModification.ReplaceNode(expr, nestedPrefix.expression, parent)) - } - val comparison = expr.expression as? BinaryExpression - if (comparison != null) { - // NOT COMPARISON ==> inverted COMPARISON - val invertedOperator = invertedComparisonOperator(comparison.operator) - if (invertedOperator != null) { - comparison.operator = invertedOperator - return listOf(IAstModification.ReplaceNode(expr, comparison, parent)) - } - } - } return noModifications } diff --git a/compiler/test/arithmetic/logical.p8 b/compiler/test/arithmetic/logical.p8 index 7b8abbab9..b4fb601f5 100644 --- a/compiler/test/arithmetic/logical.p8 +++ b/compiler/test/arithmetic/logical.p8 @@ -20,181 +20,187 @@ main { ubyte ub4 = 0 ubyte bvalue - txt.print("const not 126: ") + txt.print("const not 0: ") txt.print_ub(not 129) txt.nl() - txt.print("const not 255: ") + txt.print("const not 1: ") txt.print_ub(not 0) txt.nl() + txt.print("const inv 126: ") + txt.print_ub(~ 129) + txt.nl() + txt.print("const inv 255: ") + txt.print_ub(~ 0) + txt.nl() bvalue = 129 - txt.print("bitwise not 126: ") - bvalue = not bvalue + txt.print("bitwise inv 126: ") + bvalue = ~ bvalue txt.print_ub(bvalue) txt.nl() bvalue = 0 - txt.print("bitwise not 255: ") - bvalue = not bvalue + txt.print("bitwise inv 255: ") + bvalue = ~ bvalue txt.print_ub(bvalue) txt.nl() -; txt.print("bitwise or 14: ") -; txt.print_ub(ub1 | ub2 | ub3 | ub4) -; txt.nl() -; txt.print("bitwise or 142: ") -; txt.print_ub(ub1 | ub2 | ub3 | ub4 | 128) -; txt.nl() -; txt.print("bitwise and 0: ") -; txt.print_ub(ub1 & ub2 & ub3 & ub4) -; txt.nl() -; txt.print("bitwise and 8: ") -; txt.print_ub(ub3 & ub3 & 127) -; txt.nl() -; txt.print("bitwise xor 14: ") -; txt.print_ub(ub1 ^ ub2 ^ ub3 ^ ub4) -; txt.nl() -; txt.print("bitwise xor 6: ") -; txt.print_ub(ub1 ^ ub2 ^ ub3 ^ 8) -; txt.nl() -; txt.print("bitwise not 247: ") -; txt.print_ub(~ub3) -; txt.nl() -; txt.print("bitwise not 255: ") -; txt.print_ub(~ub4) -; txt.nl() -; -; txt.print("not 0: ") -; bvalue = 3 * (ub4 | not (ub3 | ub3 | ub3)) -; txt.print_ub(bvalue) -; if 3*(ub4 | not (ub1 | ub1 | ub1)) -; txt.print(" / fail") -; else -; txt.print(" / ok") -; txt.nl() -; -; txt.print("not 0: ") -; bvalue = not ub3 -; txt.print_ub(bvalue) -; if not ub1 -; txt.print(" / fail") -; else -; txt.print(" / ok") -; txt.nl() -; -; txt.print("not 1: ") -; bvalue = not ub4 -; txt.print_ub(bvalue) -; if not ub4 -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; -; bvalue = bvalue and 128 -; txt.print("bvl 1: ") -; txt.print_ub(bvalue) -; if bvalue and 128 -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; -; txt.print("and 1: ") -; bvalue = ub1 and ub2 and ub3 -; txt.print_ub(bvalue) -; if ub1 and ub2 and ub3 -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; txt.print("and 1: ") -; bvalue = ub1 and ub2 and ub3 and 64 -; txt.print_ub(bvalue) -; if ub1 and ub2 and ub3 and 64 -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; txt.print("and 1: ") -; bvalue = ub1 and ub2 and ub3 and ftrue(99) -; txt.print_ub(bvalue) -; if ub1 and ub2 and ub3 and ftrue(99) -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; txt.print("and 0: ") -; bvalue = ub1 and ub2 and ub3 and ub4 -; txt.print_ub(bvalue) -; if ub1 and ub2 and ub3 and ub4 -; txt.print(" / fail") -; else -; txt.print(" / ok") -; txt.nl() -; txt.print("and 0: ") -; bvalue = ub1 and ub2 and ub3 and ffalse(99) -; txt.print_ub(bvalue) -; if ub1 and ub2 and ub3 and ffalse(99) -; txt.print(" / fail") -; else -; txt.print(" / ok") -; txt.nl() -; -; txt.print(" or 1: ") -; bvalue = ub1 or ub2 or ub3 or ub4 -; txt.print_ub(bvalue) -; if ub1 or ub2 or ub3 or ub4 -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; txt.print(" or 1: ") -; bvalue = ub4 or ub4 or ub1 -; txt.print_ub(bvalue) -; if ub4 or ub4 or ub1 -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; txt.print(" or 1: ") -; bvalue = ub1 or ub2 or ub3 or ftrue(99) -; txt.print_ub(bvalue) -; if ub1 or ub2 or ub3 or ftrue(99) -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; -; txt.print("xor 1: ") -; bvalue = ub1 xor ub2 xor ub3 xor ub4 -; txt.print_ub(bvalue) -; if ub1 xor ub2 xor ub3 xor ub4 -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; txt.print("xor 1: ") -; bvalue = ub1 xor ub2 xor ub3 xor ffalse(99) -; txt.print_ub(bvalue) -; if ub1 xor ub2 xor ub3 xor ffalse(99) -; txt.print(" / ok") -; else -; txt.print(" / fail") -; txt.nl() -; -; txt.print("xor 0: ") -; bvalue = ub1 xor ub2 xor ub3 xor ub4 xor true -; txt.print_ub(bvalue) -; if ub1 xor ub2 xor ub3 xor ub4 xor true -; txt.print(" / fail") -; else -; txt.print(" / ok") -; txt.nl() -; txt.print("xor 0: ") -; bvalue = ub1 xor ub2 xor ub3 xor ftrue(99) -; txt.print_ub(bvalue) -; if ub1 xor ub2 xor ub3 xor ftrue(99) -; txt.print(" / fail") -; else -; txt.print(" / ok") + txt.print("bitwise or 14: ") + txt.print_ub(ub1 | ub2 | ub3 | ub4) + txt.nl() + txt.print("bitwise or 142: ") + txt.print_ub(ub1 | ub2 | ub3 | ub4 | 128) + txt.nl() + txt.print("bitwise and 0: ") + txt.print_ub(ub1 & ub2 & ub3 & ub4) + txt.nl() + txt.print("bitwise and 8: ") + txt.print_ub(ub3 & ub3 & 127) + txt.nl() + txt.print("bitwise xor 14: ") + txt.print_ub(ub1 ^ ub2 ^ ub3 ^ ub4) + txt.nl() + txt.print("bitwise xor 6: ") + txt.print_ub(ub1 ^ ub2 ^ ub3 ^ 8) + txt.nl() + txt.print("bitwise not 247: ") + txt.print_ub(~ub3) + txt.nl() + txt.print("bitwise not 255: ") + txt.print_ub(~ub4) + txt.nl() + + txt.print("not 0: ") + bvalue = 3 * (ub4 | not (ub3 | ub3 | ub3)) + txt.print_ub(bvalue) + if 3*(ub4 | not (ub1 | ub1 | ub1)) + txt.print(" / fail") + else + txt.print(" / ok") + txt.nl() + + txt.print("not 0: ") + bvalue = not ub3 + txt.print_ub(bvalue) + if not ub1 + txt.print(" / fail") + else + txt.print(" / ok") + txt.nl() + + txt.print("not 1: ") + bvalue = not ub4 + txt.print_ub(bvalue) + if not ub4 + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + + bvalue = bvalue and 128 + txt.print("bvl 1: ") + txt.print_ub(bvalue) + if bvalue and 128 + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + + txt.print("and 1: ") + bvalue = ub1 and ub2 and ub3 + txt.print_ub(bvalue) + if ub1 and ub2 and ub3 + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + txt.print("and 1: ") + bvalue = ub1 and ub2 and ub3 and 64 + txt.print_ub(bvalue) + if ub1 and ub2 and ub3 and 64 + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + txt.print("and 1: ") + bvalue = ub1 and ub2 and ub3 and ftrue(99) + txt.print_ub(bvalue) + if ub1 and ub2 and ub3 and ftrue(99) + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + txt.print("and 0: ") + bvalue = ub1 and ub2 and ub3 and ub4 + txt.print_ub(bvalue) + if ub1 and ub2 and ub3 and ub4 + txt.print(" / fail") + else + txt.print(" / ok") + txt.nl() + txt.print("and 0: ") + bvalue = ub1 and ub2 and ub3 and ffalse(99) + txt.print_ub(bvalue) + if ub1 and ub2 and ub3 and ffalse(99) + txt.print(" / fail") + else + txt.print(" / ok") + txt.nl() + + txt.print(" or 1: ") + bvalue = ub1 or ub2 or ub3 or ub4 + txt.print_ub(bvalue) + if ub1 or ub2 or ub3 or ub4 + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + txt.print(" or 1: ") + bvalue = ub4 or ub4 or ub1 + txt.print_ub(bvalue) + if ub4 or ub4 or ub1 + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + txt.print(" or 1: ") + bvalue = ub1 or ub2 or ub3 or ftrue(99) + txt.print_ub(bvalue) + if ub1 or ub2 or ub3 or ftrue(99) + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + + txt.print("xor 1: ") + bvalue = ub1 xor ub2 xor ub3 xor ub4 + txt.print_ub(bvalue) + if ub1 xor ub2 xor ub3 xor ub4 + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + txt.print("xor 1: ") + bvalue = ub1 xor ub2 xor ub3 xor ffalse(99) + txt.print_ub(bvalue) + if ub1 xor ub2 xor ub3 xor ffalse(99) + txt.print(" / ok") + else + txt.print(" / fail") + txt.nl() + + txt.print("xor 0: ") + bvalue = ub1 xor ub2 xor ub3 xor ub4 xor true + txt.print_ub(bvalue) + if ub1 xor ub2 xor ub3 xor ub4 xor true + txt.print(" / fail") + else + txt.print(" / ok") + txt.nl() + txt.print("xor 0: ") + bvalue = ub1 xor ub2 xor ub3 xor ftrue(99) + txt.print_ub(bvalue) + if ub1 xor ub2 xor ub3 xor ftrue(99) + txt.print(" / fail") + else + txt.print(" / ok") } } diff --git a/compiler/test/ast/TestProg8Parser.kt b/compiler/test/ast/TestProg8Parser.kt index 4a19a563d..bee0a0773 100644 --- a/compiler/test/ast/TestProg8Parser.kt +++ b/compiler/test/ast/TestProg8Parser.kt @@ -745,7 +745,7 @@ class TestProg8Parser: FunSpec( { main { ubyte bb uword ww - ubyte bb2 = not bb or not ww ; expression combining ubyte and uword + ubyte bb2 = (3+bb) or (3333+ww) ; expression combining ubyte and uword } """) val module = parseModule(src) diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index d0a21279d..c64e8d8d7 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -109,7 +109,6 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid DataType.UWORD -> NumericLiteral(DataType.UWORD, (constval.number.toInt().inv() and 65535).toDouble(), constval.position) else -> throw ExpressionError("can only take bitwise inversion of int", constval.position) } - "not" -> NumericLiteral.fromBoolean(constval.number == 0.0, constval.position) else -> throw FatalAstException("invalid operator") } converted.linkParents(this.parent) @@ -124,10 +123,6 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid return when(operator) { "+" -> inferred "~", "not" -> { - // note: "not" should ideally result in UBYTE (boolean) but the way the type system - // currently works means the result of an operator is the same type as the operand(s). - // So not(byte)->byte, not(word)->word. This is taken care of via a cast to ubyte later. - // If we give not a BYTE type here, the asmassignment validation will sometimes crash. when(inferred.getOr(DataType.UNDEFINED)) { in ByteDatatypes -> InferredTypes.knownFor(DataType.UBYTE) in WordDatatypes -> InferredTypes.knownFor(DataType.UWORD) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index a97dc91b7..b62fb86a1 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,18 +3,22 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- 6502: fix not codegen to be bitwise not instead of boolean not (maybe need to change boolean() wrapping / variouscleanups) - all these testable with compiler/test/arithmetic/logical.p8 -- 6502: also fix logical and/or/xor routines to just be bitwise routines. +- chess.prg became A LOT larger, why!? (perhaps due to new while/until condition handling?) +- imageviewer.prg became A LOT larger, why!? +- petaxian.prg became A LOT larger, why!? +- some programs became a bit larger since "not" was removed (assembler) -- get rid of logical and/or/xor/not in the codegen (6502+vm) +- 6502: fix logical and/or/xor routines to just be bitwise routines. + +- get rid of logical and/or/xor in the codegen (6502+vm) because bitwise versions + correct use of boolean() operand wrapping are equivalent? - can do this for instance by replacing and/or/xor/not with their bitwise versions &, |, ^, ~ + can do this for instance by replacing and/or/xor with their bitwise versions &, |, ^, ~ - compiling logical.p8 to virtual with optimization generates a lot larger code as without optimizations. this is not the case for the 6502 codegen. -- add optimizations: not a or not b -> not(a and b) , not a and not b -> not(a or b) +- add optimizations: not a or not b -> not(a and b) , not a and not b -> not(a or b) + actually this now means: (a==0) or (b==0) -> (a or b)==0, (a==0) and (b==0) -> (a or b)==0 add unit tests for that. - bin expr splitter: split logical expressions on ands/ors/xors ? diff --git a/virtualmachine/src/prog8/vm/Instructions.kt b/virtualmachine/src/prog8/vm/Instructions.kt index 727869841..a144b9158 100644 --- a/virtualmachine/src/prog8/vm/Instructions.kt +++ b/virtualmachine/src/prog8/vm/Instructions.kt @@ -124,7 +124,7 @@ All have type b or w. and reg1, reg2 - reg1 = reg1 bitwise and reg2 or reg1, reg2 - reg1 = reg1 bitwise or reg2 xor reg1, reg2 - reg1 = reg1 bitwise xor reg2 -not reg1 - reg1 = bitwise not of reg1 (all bits flipped) +inv reg1 - reg1 = bitwise invert of reg1 (all bits flipped) lsrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits + set Carry to shifted bit asrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits (signed) + set Carry to shifted bit lsln reg1, reg2 - reg1 = multi-shift reg1 left by reg2 bits + set Carry to shifted bit @@ -138,7 +138,7 @@ roxl reg1 - rotate reg1 left by 1 bits, using andm reg1 address - memory = memory bitwise and reg1 orm reg1, address - memory = memory bitwise or reg1 xorm reg1, address - memory = memory bitwise xor reg1 -notm address - memory = bitwise not of that memory (all bits flipped) +invm address - memory = bitwise invert of that memory (all bits flipped) lsrnm reg1, address - multi-shift memoryright by reg1 bits + set Carry to shifted bit asrnm reg1, address - multi-shift memory right by reg1 bits (signed) + set Carry to shifted bit lslnm reg1, address - multi-shift memory left by reg1 bits + set Carry to shifted bit @@ -260,8 +260,8 @@ enum class Opcode { ORM, XOR, XORM, - NOT, - NOTM, + INV, + INVM, ASRN, ASRNM, LSRN, @@ -330,7 +330,7 @@ val OpcodesWithAddress = setOf( Opcode.MULM, Opcode.DIVM, Opcode.DIVSM, - Opcode.NOTM, + Opcode.INVM, Opcode.ORM, Opcode.XORM, Opcode.ANDM, @@ -556,8 +556,8 @@ val instructionFormats = mutableMapOf( Opcode.ORM to InstructionFormat.from("BW,r1,v"), Opcode.XOR to InstructionFormat.from("BW,r1,r2"), Opcode.XORM to InstructionFormat.from("BW,r1,v"), - Opcode.NOT to InstructionFormat.from("BW,r1"), - Opcode.NOTM to InstructionFormat.from("BW,v"), + Opcode.INV to InstructionFormat.from("BW,r1"), + Opcode.INVM to InstructionFormat.from("BW,v"), Opcode.ASRN to InstructionFormat.from("BW,r1,r2"), Opcode.ASRNM to InstructionFormat.from("BW,r1,v"), Opcode.LSRN to InstructionFormat.from("BW,r1,r2"), diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 2c6edc913..7244c26f5 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -162,8 +162,8 @@ class VirtualMachine(val memory: Memory, program: List) { Opcode.ORM -> InsORM(ins) Opcode.XOR -> InsXOR(ins) Opcode.XORM ->InsXORM(ins) - Opcode.NOT -> InsNOT(ins) - Opcode.NOTM -> InsNOTM(ins) + Opcode.INV -> InsINV(ins) + Opcode.INVM -> InsINVM(ins) Opcode.ASRN -> InsASRN(ins) Opcode.LSRN -> InsLSRN(ins) Opcode.LSLN -> InsLSLN(ins) @@ -1216,7 +1216,7 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } - private fun InsNOT(i: Instruction) { + private fun InsINV(i: Instruction) { when(i.type!!) { VmDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg1).inv()) VmDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(i.reg1).inv()) @@ -1225,7 +1225,7 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } - private fun InsNOTM(i: Instruction) { + private fun InsINVM(i: Instruction) { val address = i.value!! when(i.type!!) { VmDataType.BYTE -> memory.setUB(address, memory.getUB(address).inv())