"not" operator removed from ast and codegen (it's been replaced with x==0 as equivalent)

This commit is contained in:
Irmen de Jong
2022-06-29 01:13:08 +02:00
parent dc82a0fc16
commit 4b358abbb7
22 changed files with 216 additions and 433 deletions
@@ -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)
}
+1 -1
View File
@@ -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) =
@@ -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}")
}
}
@@ -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")
}
}
@@ -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 -> {
@@ -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
@@ -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)
@@ -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)
}
}
@@ -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(
-21
View File
@@ -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
@@ -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)
@@ -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<IAstModification> {
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))
}
@@ -169,18 +169,6 @@ internal class BeforeAsmAstChanger(val program: Program,
}
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
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
@@ -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),
@@ -102,19 +102,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
return noModifications
}
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
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<IAstModification> {
// see if a typecast is needed to convert the value's type into the proper target type
val valueItype = assignment.value.inferType(program)
@@ -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
}
+171 -165
View File
@@ -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")
}
}
+1 -1
View File
@@ -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)
@@ -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)
+10 -6
View File
@@ -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 ?
+7 -7
View File
@@ -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"),
@@ -162,8 +162,8 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
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<Instruction>) {
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<Instruction>) {
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())