From 79419a98d0fb1176e57dfec5653dd3ce02b4764d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 11 Sep 2025 01:57:30 +0200 Subject: [PATCH] add if-expression versions for the conditionals if_cc, if_cs, if_vc etc --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 6 +- .../codegen/cpu6502/IfExpressionAsmGen.kt | 63 ++++++++++++++++++ .../cpu6502/assignment/AssignmentAsmGen.kt | 1 + .../codegen/intermediate/ExpressionGen.kt | 64 +++++++++++++++++++ .../prog8/codegen/intermediate/IRCodeGen.kt | 2 +- .../intermediate/IRPeepholeOptimizer.kt | 24 +++++++ .../astprocessing/SimplifiedAstMaker.kt | 9 +++ .../src/prog8/ast/AstToSourceTextConverter.kt | 7 ++ .../prog8/ast/antlr/Antlr2KotlinVisitor.kt | 6 +- .../prog8/ast/expressions/AstExpressions.kt | 36 +++++++++++ compilerAst/src/prog8/ast/walk/AstWalker.kt | 9 +++ compilerAst/src/prog8/ast/walk/IAstVisitor.kt | 5 ++ docs/source/programming.rst | 6 ++ docs/source/todo.rst | 1 - examples/test.p8 | 49 ++++++++++---- .../src/prog8/intermediate/IRInstructions.kt | 17 +++++ .../src/prog8/code/ast/AstExpressions.kt | 7 ++ simpleAst/src/prog8/code/ast/AstPrinter.kt | 1 + 18 files changed, 294 insertions(+), 19 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index b743002a1..5bb5ff046 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -860,7 +860,7 @@ class AsmGen6502Internal ( } } - private fun branchInstruction(condition: BranchCondition, complement: Boolean) = + internal fun branchInstruction(condition: BranchCondition, complement: Boolean) = if(complement) { when (condition) { BranchCondition.CS -> "bcc" @@ -1698,6 +1698,10 @@ $repeatLabel""") ifExpressionAsmgen.assignIfExpression(target, value) } + internal fun assignBranchCondExpression(target: AsmAssignTarget, value: PtBranchCondExpression) { + ifExpressionAsmgen.assignBranchCondExpression(target, value) + } + internal fun cmpAwithByteValue(value: PtExpression, useSbc: Boolean) { val compare = if(useSbc) "sec | sbc" else "cmp" fun cmpViaScratch() { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfExpressionAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfExpressionAsmGen.kt index d3323fabe..6be52f1e6 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfExpressionAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfExpressionAsmGen.kt @@ -44,6 +44,69 @@ internal class IfExpressionAsmGen(private val asmgen: AsmGen6502Internal, privat } } + internal fun assignBranchCondExpression(target: AsmAssignTarget, expr: PtBranchCondExpression) { + require(target.datatype==expr.type || + target.datatype.isUnsignedWord && (expr.type.isString || expr.type.isPointer) || + target.datatype.isPointer && (expr.type.isUnsignedWord || expr.type.isPointer || expr.type.isString)) + + if(target.kind==TargetStorageKind.REGISTER && target.datatype.isUnsignedByte && target.register==RegisterOrPair.A) { + if(expr.condition==BranchCondition.CC) { + if(expr.truevalue.asConstInteger()==0 && expr.falsevalue.asConstInteger()==1) { + asmgen.out(" lda #0 | rol a") + return + } + else if(expr.truevalue.asConstInteger()==1 && expr.falsevalue.asConstInteger()==0) { + asmgen.out(" lda #0 | rol a | eor #1") + return + } + } + else if(expr.condition==BranchCondition.CS) { + if(expr.truevalue.asConstInteger()==0 && expr.falsevalue.asConstInteger()==1) { + asmgen.out(" lda #0 | rol a | eor #1") + return + } + else if(expr.truevalue.asConstInteger()==1 && expr.falsevalue.asConstInteger()==0) { + asmgen.out(" lda #0 | rol a") + return + } + } + } + + val trueLabel = asmgen.makeLabel("branchexpr_true") + val endLabel = asmgen.makeLabel("branchexpr_end") + val branch = asmgen.branchInstruction(expr.condition, false) + + asmgen.out(" $branch $trueLabel") + + when { + expr.type.isByteOrBool -> { + asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A) + asmgen.jmp(endLabel) + asmgen.out(trueLabel) + asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.A) + asmgen.out(endLabel) + assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, false, false) + } + expr.type.isWord || expr.type.isString -> { + asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.AY) + asmgen.jmp(endLabel) + asmgen.out(trueLabel) + asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY) + asmgen.out(endLabel) + assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY) + } + expr.type.isFloat -> { + asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.FAC1, true) + asmgen.jmp(endLabel) + asmgen.out(trueLabel) + asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true) + asmgen.out(endLabel) + asmgen.assignRegister(RegisterOrPair.FAC1, target) + } + else -> throw AssemblyError("weird dt") + } + } + private fun evalIfExpressionConditonAndBranchWhenFalse(condition: PtExpression, falseLabel: String) { when (condition) { is PtBinaryExpression -> { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 63fe26a3b..9650b9da3 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -526,6 +526,7 @@ internal class AssignmentAsmGen( } } is PtIfExpression -> asmgen.assignIfExpression(assign.target, value) + is PtBranchCondExpression -> asmgen.assignBranchCondExpression(assign.target, value) is PtPointerDeref -> pointergen.assignPointerDerefExpression(assign.target, value) else -> throw AssemblyError("weird assignment value type $value") } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index b70eec1d1..77de35bb1 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -83,6 +83,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { is PtArrayIndexer -> translate(expr) is PtBinaryExpression -> translate(expr) is PtIfExpression -> translate(expr) + is PtBranchCondExpression -> translate(expr) is PtBuiltinFunctionCall -> codeGen.translateBuiltinFunc(expr) is PtFunctionCall -> translate(expr) is PtContainmentCheck -> translate(expr) @@ -253,6 +254,69 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } } + private fun translate(branchExpr: PtBranchCondExpression): ExpressionCodeResult { + val result = mutableListOf() + val trueTr = translateExpression(branchExpr.truevalue) + val falseTr = translateExpression(branchExpr.falsevalue) + val trueLabel = codeGen.createLabelName() + val endLabel = codeGen.createLabelName() + val irDt = irType(branchExpr.type) + + if(branchExpr.condition==BranchCondition.CC && irDt==IRDataType.BYTE) { + if(branchExpr.truevalue.asConstInteger()==0 && branchExpr.falsevalue.asConstInteger()==1) { + result.add(IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, irDt, reg1=trueTr.resultReg, immediate = 0) + it += IRInstruction(Opcode.ROXL, irDt, reg1=trueTr.resultReg) + }) + return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1) + } + else if(branchExpr.truevalue.asConstInteger()==1 && branchExpr.falsevalue.asConstInteger()==0) { + result.add(IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, irDt, reg1=trueTr.resultReg, immediate = 0) + it += IRInstruction(Opcode.ROXL, irDt, reg1=trueTr.resultReg) + it += IRInstruction(Opcode.XOR, irDt, reg1=trueTr.resultReg, immediate = 1) + }) + return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1) + } + } + else if(branchExpr.condition==BranchCondition.CS) { + if(branchExpr.truevalue.asConstInteger()==0 && branchExpr.falsevalue.asConstInteger()==1) { + result.add(IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, irDt, reg1=trueTr.resultReg, immediate = 0) + it += IRInstruction(Opcode.ROXL, irDt, reg1=trueTr.resultReg) + it += IRInstruction(Opcode.XOR, irDt, reg1=trueTr.resultReg, immediate = 1) + }) + return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1) + } + else if(branchExpr.truevalue.asConstInteger()==1 && branchExpr.falsevalue.asConstInteger()==0) { + result.add(IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, irDt, reg1=trueTr.resultReg, immediate = 0) + it += IRInstruction(Opcode.ROXL, irDt, reg1=trueTr.resultReg) + }) + return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1) + } + } + + val branchInstr = codeGen.IRBranchInstr(branchExpr.condition, trueLabel) + addInstr(result, branchInstr, null) + + if (irDt != IRDataType.FLOAT) { + addToResult(result, falseTr, trueTr.resultReg, -1) + addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null) + result += IRCodeChunk(trueLabel, null) + addToResult(result, trueTr, trueTr.resultReg, -1) + result += IRCodeChunk(endLabel, null) + return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1) + } else { + addToResult(result, falseTr, -1, trueTr.resultFpReg) + addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null) + result += IRCodeChunk(trueLabel, null) + addToResult(result, trueTr, -1, trueTr.resultFpReg) + result += IRCodeChunk(endLabel, null) + return ExpressionCodeResult(result, irDt, -1, trueTr.resultFpReg) + } + } + private fun translate(expr: PtAddressOf): ExpressionCodeResult { val vmDt = irType(expr.type) // note: LOAD gets you the address of the symbol, whereas LOADM would get you the value stored at that location diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index a4ef911b0..4a3a5a54d 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -336,7 +336,7 @@ class IRCodeGen( return result } - private fun IRBranchInstr(condition: BranchCondition, label: String?=null, address: Int?=null): IRInstruction { + internal fun IRBranchInstr(condition: BranchCondition, label: String?=null, address: Int?=null): IRInstruction { if(label!=null) return when(condition) { BranchCondition.CS -> IRInstruction(Opcode.BSTCS, labelSymbol = label) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index ea6a155cb..e62a380ac 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -54,6 +54,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { || removeDoubleSecClc(chunk1, indexedInstructions) || cleanupPushPop(chunk1, indexedInstructions) || simplifyConstantReturns(chunk1, indexedInstructions) + || removeNeedlessLoads(chunk1, indexedInstructions) } while (changed) } } @@ -353,6 +354,29 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { return changed } + private fun removeNeedlessLoads(chunk: IRCodeChunk, indexedInstructions: List>): Boolean { + /* +load.b r2,#2 +loadr.b r1,r2 +jump p8_label_gen_2 + */ + var changed=false + indexedInstructions.reversed().forEach { (idx, ins) -> + if(idx>=2 && ins.opcode in OpcodesThatJump) { + val previous = indexedInstructions[idx-1].value + val previous2 = indexedInstructions[idx-2].value + if(previous.opcode==Opcode.LOADR && previous2.opcode in OpcodesThatLoad) { + if(previous.reg2==previous2.reg1) { + chunk.instructions[idx-2] = previous2.copy(reg1=previous.reg1) + chunk.instructions.removeAt(idx-1) + changed=true + } + } + } + } + return changed + } + private fun removeUselessArithmetic(chunk: IRCodeChunk, indexedInstructions: List>): Boolean { // note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first var changed = false diff --git a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt index 8d5e62c4c..43f95ab91 100644 --- a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt @@ -100,6 +100,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro is StringLiteral -> transform(expr) is TypecastExpression -> transform(expr) is IfExpression -> transform(expr) + is BranchConditionExpression -> transform(expr) is PtrDereference -> transform(expr) is StaticStructInitializer -> transform(expr) is ArrayIndexedPtrDereference -> throw FatalAstException("this should have been converted to some other ast nodes") @@ -141,6 +142,14 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro return ifexpr } + private fun transform(branchExpr: BranchConditionExpression): PtBranchCondExpression { + val type = branchExpr.inferType(program).getOrElse { throw FatalAstException("unknown dt") } + val bexpr = PtBranchCondExpression(branchExpr.condition, type, branchExpr.position) + bexpr.add(transformExpression(branchExpr.truevalue)) + bexpr.add(transformExpression(branchExpr.falsevalue)) + return bexpr + } + private fun transform(srcDefer: Defer): PtDefer { val defer = PtDefer(srcDefer.position) srcDefer.scope.statements.forEach { diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index a2ac5e677..5cce53f5a 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -66,6 +66,13 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: ifExpr.falsevalue.accept(this) } + override fun visit(branchExpr: BranchConditionExpression) { + output("if_${branchExpr.condition.name.lowercase()} ") + branchExpr.truevalue.accept(this) + output(" else ") + branchExpr.falsevalue.accept(this) + } + override fun visit(continueStmt: Continue) { output("continue") } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2KotlinVisitor.kt b/compilerAst/src/prog8/ast/antlr/Antlr2KotlinVisitor.kt index 1fd5ed364..27037288c 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2KotlinVisitor.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2KotlinVisitor.kt @@ -551,10 +551,10 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor): Boolean = truevalue.referencesIdentifier(nameInSource) || falsevalue.referencesIdentifier(nameInSource) + override fun inferType(program: Program): InferredTypes.InferredType { + val t1 = truevalue.inferType(program) + val t2 = falsevalue.inferType(program) + if(t1==t2) return t1 + if(t1.isPointer && t2.isUnsignedWord || t1.isUnsignedWord && t2.isPointer) return InferredTypes.knownFor(BaseDataType.UWORD) + return InferredTypes.unknown() + } + + override fun copy(): Expression = BranchConditionExpression(condition, truevalue.copy(), falsevalue.copy(), position) + + override fun replaceChildNode(node: Node, replacement: Node) { + if(replacement !is Expression) + throw FatalAstException("invalid replace") + else if(node===truevalue) truevalue=replacement + else if(node===falsevalue) falsevalue=replacement + else throw FatalAstException("invalid replace") + } +} + class PtrDereference( val chain: List, val derefLast: Boolean, diff --git a/compilerAst/src/prog8/ast/walk/AstWalker.kt b/compilerAst/src/prog8/ast/walk/AstWalker.kt index dbc9f54fc..9ca8763b2 100644 --- a/compilerAst/src/prog8/ast/walk/AstWalker.kt +++ b/compilerAst/src/prog8/ast/walk/AstWalker.kt @@ -114,6 +114,7 @@ abstract class AstWalker { open fun before(expr: BinaryExpression, parent: Node): Iterable = noModifications open fun before(expr: PrefixExpression, parent: Node): Iterable = noModifications open fun before(ifExpr: IfExpression, parent: Node): Iterable = noModifications + open fun before(branchExpr: BranchConditionExpression, parent: Node): Iterable = noModifications open fun before(forLoop: ForLoop, parent: Node): Iterable = noModifications open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable = noModifications open fun before(unrollLoop: UnrollLoop, parent: Node): Iterable = noModifications @@ -165,6 +166,7 @@ abstract class AstWalker { open fun after(expr: BinaryExpression, parent: Node): Iterable = noModifications open fun after(expr: PrefixExpression, parent: Node): Iterable = noModifications open fun after(ifExpr: IfExpression, parent: Node): Iterable = noModifications + open fun after(branchExpr: BranchConditionExpression, parent: Node): Iterable = noModifications open fun after(forLoop: ForLoop, parent: Node): Iterable = noModifications open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable = noModifications open fun after(unrollLoop: UnrollLoop, parent: Node): Iterable = noModifications @@ -510,6 +512,13 @@ abstract class AstWalker { track(after(ifExpr, parent), ifExpr, parent) } + fun visit(branchExpr: BranchConditionExpression, parent: Node) { + track(before(branchExpr, parent), branchExpr, parent) + branchExpr.truevalue.accept(this, branchExpr) + branchExpr.falsevalue.accept(this, branchExpr) + track(after(branchExpr, parent), branchExpr, parent) + } + fun visit(inlineAssembly: InlineAssembly, parent: Node) { track(before(inlineAssembly, parent), inlineAssembly, parent) track(after(inlineAssembly, parent), inlineAssembly, parent) diff --git a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt index 03f23ee53..7374839bd 100644 --- a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt +++ b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt @@ -100,6 +100,11 @@ interface IAstVisitor { ifExpr.falsevalue.accept(this) } + fun visit(branchExpr: BranchConditionExpression) { + branchExpr.truevalue.accept(this) + branchExpr.falsevalue.accept(this) + } + fun visit(label: Label) { } diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 09f390ccd..ef7b26e24 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -742,6 +742,12 @@ An example, to select the number of cards to use depending on what game is playe else numcards = 52 +The expression form is also available for the conditionals ``if_cc``, ``if_cs``, ``if_z`` etc. +(These particular variants for checking the value of the Carry status bit actually compile into very efficient branchless assembly code):: + + ubyte carryvalue = if_cs 1 else 0 + + on .. goto / on .. call statement (jump table) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 32b682013..4d833b388 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -78,7 +78,6 @@ STRUCTS and TYPED POINTERS Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ -- add if-expression versions for the conditionals if_cc, if_cs, if_vc etc etc so you can write a = b + if_cs 1 else 0 (make sure it gets compiled to nice instructions lda #0; rol a etc.) See visitBranchcondition_expression() - %breakpoint after an assignment is parsed as part of the expression (x % breakpoint), that should not happen - when a complete block is removed because unused, suppress all info messages about everything in the block being removed - fix the line, cols in Position, sometimes they count from 0 sometimes from 1 diff --git a/examples/test.p8 b/examples/test.p8 index e321a73be..3f3f5ad44 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,19 +1,42 @@ +%import textio %zeropage basicsafe main { - struct Node { - ubyte id - } - - ^^byte @shared bptr = 2000 - ^^word @shared swptr = 2000 - ^^uword @shared uwptr = 2000 - ^^Node @shared node = 2000 - sub start() { - alias nid = node.id - cx16.r0 = mkword(0, cx16.r9L) - swptr^^ = mkword(0, cx16.r9L) as word - uwptr^^ = mkword(0, cx16.r9L) + sys.set_carry() + txt.print_ub(if_cc 0 else 1) + txt.nl() + sys.clear_carry() + txt.print_ub(if_cc 0 else 1) + txt.nl() + sys.set_carry() + txt.print_ub(if_cs 0 else 1) + txt.nl() + sys.clear_carry() + txt.print_ub(if_cs 0 else 1) + txt.nl() } } + +;%import textio +;%zeropage basicsafe +; +;main { +; struct Node { +; ubyte id +; str name +; uword array +; } +; +; ^^Node @shared @zp node = 2000 +; +; sub start() { +; txt.print_uw(node) +; txt.spc() +; cx16.r0 = &node.array ; TODO don't clobber node pointer itself!! +; txt.print_uw(cx16.r0) +; txt.spc() +; txt.print_uw(node) +; txt.nl() +; } +;} diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index e43fb4f7e..50f97b077 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -514,6 +514,23 @@ val OpcodesThatDependOnCarry = arrayOf( Opcode.ROXRM ) +val OpcodesThatLoad = arrayOf( + Opcode.LOAD, + Opcode.LOADM, + Opcode.LOADI, + Opcode.LOADX, + Opcode.LOADIX, + Opcode.LOADR, + Opcode.LOADHA, + Opcode.LOADHX, + Opcode.LOADHY, + Opcode.LOADHAX, + Opcode.LOADHAY, + Opcode.LOADHXY, + Opcode.LOADFIELD, + Opcode.LOADHFACZERO, + Opcode.LOADHFACONE +) val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThatSetStatusbitsIncludingCarry diff --git a/simpleAst/src/prog8/code/ast/AstExpressions.kt b/simpleAst/src/prog8/code/ast/AstExpressions.kt index 7ff41e123..965246b47 100644 --- a/simpleAst/src/prog8/code/ast/AstExpressions.kt +++ b/simpleAst/src/prog8/code/ast/AstExpressions.kt @@ -141,6 +141,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit is PtPointerDeref -> false is PtTypeCast -> value.isSimple() is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple() + is PtBranchCondExpression -> truevalue.isSimple() && falsevalue.isSimple() } } @@ -259,6 +260,12 @@ class PtIfExpression(type: DataType, position: Position): PtExpression(type, pos get() = children[2] as PtExpression } +class PtBranchCondExpression(val condition: BranchCondition, type: DataType, position: Position): PtExpression(type, position) { + val truevalue: PtExpression + get() = children[0] as PtExpression + val falsevalue: PtExpression + get() = children[1] as PtExpression +} class PtContainmentCheck(position: Position): PtExpression(DataType.BOOL, position) { val needle: PtExpression diff --git a/simpleAst/src/prog8/code/ast/AstPrinter.kt b/simpleAst/src/prog8/code/ast/AstPrinter.kt index 6da4287dc..19bb14e49 100644 --- a/simpleAst/src/prog8/code/ast/AstPrinter.kt +++ b/simpleAst/src/prog8/code/ast/AstPrinter.kt @@ -188,6 +188,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni } is PtDefer -> "" is PtIfExpression -> "" + is PtBranchCondExpression -> " if_${node.condition.name.lowercase()}" is PtJmpTable -> "" is PtStructDecl -> { "struct ${node.name} { " + node.fields.joinToString(" ") { "${it.first} ${it.second}" } + " }"