mirror of
https://github.com/irmen/prog8.git
synced 2025-11-24 06:17:39 +00:00
add if-expression versions for the conditionals if_cc, if_cs, if_vc etc
This commit is contained in:
@@ -860,7 +860,7 @@ class AsmGen6502Internal (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun branchInstruction(condition: BranchCondition, complement: Boolean) =
|
internal fun branchInstruction(condition: BranchCondition, complement: Boolean) =
|
||||||
if(complement) {
|
if(complement) {
|
||||||
when (condition) {
|
when (condition) {
|
||||||
BranchCondition.CS -> "bcc"
|
BranchCondition.CS -> "bcc"
|
||||||
@@ -1698,6 +1698,10 @@ $repeatLabel""")
|
|||||||
ifExpressionAsmgen.assignIfExpression(target, value)
|
ifExpressionAsmgen.assignIfExpression(target, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun assignBranchCondExpression(target: AsmAssignTarget, value: PtBranchCondExpression) {
|
||||||
|
ifExpressionAsmgen.assignBranchCondExpression(target, value)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun cmpAwithByteValue(value: PtExpression, useSbc: Boolean) {
|
internal fun cmpAwithByteValue(value: PtExpression, useSbc: Boolean) {
|
||||||
val compare = if(useSbc) "sec | sbc" else "cmp"
|
val compare = if(useSbc) "sec | sbc" else "cmp"
|
||||||
fun cmpViaScratch() {
|
fun cmpViaScratch() {
|
||||||
|
|||||||
@@ -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) {
|
private fun evalIfExpressionConditonAndBranchWhenFalse(condition: PtExpression, falseLabel: String) {
|
||||||
when (condition) {
|
when (condition) {
|
||||||
is PtBinaryExpression -> {
|
is PtBinaryExpression -> {
|
||||||
|
|||||||
@@ -526,6 +526,7 @@ internal class AssignmentAsmGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtIfExpression -> asmgen.assignIfExpression(assign.target, value)
|
is PtIfExpression -> asmgen.assignIfExpression(assign.target, value)
|
||||||
|
is PtBranchCondExpression -> asmgen.assignBranchCondExpression(assign.target, value)
|
||||||
is PtPointerDeref -> pointergen.assignPointerDerefExpression(assign.target, value)
|
is PtPointerDeref -> pointergen.assignPointerDerefExpression(assign.target, value)
|
||||||
else -> throw AssemblyError("weird assignment value type $value")
|
else -> throw AssemblyError("weird assignment value type $value")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
is PtArrayIndexer -> translate(expr)
|
is PtArrayIndexer -> translate(expr)
|
||||||
is PtBinaryExpression -> translate(expr)
|
is PtBinaryExpression -> translate(expr)
|
||||||
is PtIfExpression -> translate(expr)
|
is PtIfExpression -> translate(expr)
|
||||||
|
is PtBranchCondExpression -> translate(expr)
|
||||||
is PtBuiltinFunctionCall -> codeGen.translateBuiltinFunc(expr)
|
is PtBuiltinFunctionCall -> codeGen.translateBuiltinFunc(expr)
|
||||||
is PtFunctionCall -> translate(expr)
|
is PtFunctionCall -> translate(expr)
|
||||||
is PtContainmentCheck -> 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<IRCodeChunkBase>()
|
||||||
|
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 {
|
private fun translate(expr: PtAddressOf): ExpressionCodeResult {
|
||||||
val vmDt = irType(expr.type)
|
val vmDt = irType(expr.type)
|
||||||
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ class IRCodeGen(
|
|||||||
return result
|
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)
|
if(label!=null)
|
||||||
return when(condition) {
|
return when(condition) {
|
||||||
BranchCondition.CS -> IRInstruction(Opcode.BSTCS, labelSymbol = label)
|
BranchCondition.CS -> IRInstruction(Opcode.BSTCS, labelSymbol = label)
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
|| removeDoubleSecClc(chunk1, indexedInstructions)
|
|| removeDoubleSecClc(chunk1, indexedInstructions)
|
||||||
|| cleanupPushPop(chunk1, indexedInstructions)
|
|| cleanupPushPop(chunk1, indexedInstructions)
|
||||||
|| simplifyConstantReturns(chunk1, indexedInstructions)
|
|| simplifyConstantReturns(chunk1, indexedInstructions)
|
||||||
|
|| removeNeedlessLoads(chunk1, indexedInstructions)
|
||||||
} while (changed)
|
} while (changed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,6 +354,29 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun removeNeedlessLoads(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): 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<IndexedValue<IRInstruction>>): Boolean {
|
private fun removeUselessArithmetic(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||||
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
|
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
|
||||||
var changed = false
|
var changed = false
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
|||||||
is StringLiteral -> transform(expr)
|
is StringLiteral -> transform(expr)
|
||||||
is TypecastExpression -> transform(expr)
|
is TypecastExpression -> transform(expr)
|
||||||
is IfExpression -> transform(expr)
|
is IfExpression -> transform(expr)
|
||||||
|
is BranchConditionExpression -> transform(expr)
|
||||||
is PtrDereference -> transform(expr)
|
is PtrDereference -> transform(expr)
|
||||||
is StaticStructInitializer -> transform(expr)
|
is StaticStructInitializer -> transform(expr)
|
||||||
is ArrayIndexedPtrDereference -> throw FatalAstException("this should have been converted to some other ast nodes")
|
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
|
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 {
|
private fun transform(srcDefer: Defer): PtDefer {
|
||||||
val defer = PtDefer(srcDefer.position)
|
val defer = PtDefer(srcDefer.position)
|
||||||
srcDefer.scope.statements.forEach {
|
srcDefer.scope.statements.forEach {
|
||||||
|
|||||||
@@ -66,6 +66,13 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
|||||||
ifExpr.falsevalue.accept(this)
|
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) {
|
override fun visit(continueStmt: Continue) {
|
||||||
output("continue")
|
output("continue")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -551,10 +551,10 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
|||||||
return IfExpression(condition, truevalue, falsevalue, ctx.toPosition())
|
return IfExpression(condition, truevalue, falsevalue, ctx.toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBranchcondition_expression(ctx: Branchcondition_expressionContext): IfExpression {
|
override fun visitBranchcondition_expression(ctx: Branchcondition_expressionContext): BranchConditionExpression {
|
||||||
val branchcondition = branchCondition(ctx.branchcondition())
|
val condition = branchCondition(ctx.branchcondition())
|
||||||
val (truevalue, falsevalue) = ctx.expression().map { it.accept(this) as Expression }
|
val (truevalue, falsevalue) = ctx.expression().map { it.accept(this) as Expression }
|
||||||
throw SyntaxError("branchcondition expression not yet supported", ctx.toPosition())
|
return BranchConditionExpression(condition, truevalue, falsevalue, ctx.toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBranch_stmt(ctx: Branch_stmtContext): ConditionalBranch {
|
override fun visitBranch_stmt(ctx: Branch_stmtContext): ConditionalBranch {
|
||||||
|
|||||||
@@ -1660,6 +1660,42 @@ class IfExpression(var condition: Expression, var truevalue: Expression, var fal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BranchConditionExpression(var condition: BranchCondition, var truevalue: Expression, var falsevalue: Expression, override val position: Position) : Expression() {
|
||||||
|
|
||||||
|
override lateinit var parent: Node
|
||||||
|
|
||||||
|
override fun linkParents(parent: Node) {
|
||||||
|
this.parent = parent
|
||||||
|
truevalue.linkParents(this)
|
||||||
|
falsevalue.linkParents(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val isSimple: Boolean = truevalue.isSimple && falsevalue.isSimple
|
||||||
|
|
||||||
|
override fun constValue(program: Program) = null
|
||||||
|
override fun toString() = "BranchExpr(cond=$condition, true=$truevalue, false=$falsevalue, pos=$position)"
|
||||||
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
|
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||||
|
override fun referencesIdentifier(nameInSource: List<String>): 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(
|
class PtrDereference(
|
||||||
val chain: List<String>,
|
val chain: List<String>,
|
||||||
val derefLast: Boolean,
|
val derefLast: Boolean,
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ abstract class AstWalker {
|
|||||||
open fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
|
open fun before(branchExpr: BranchConditionExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(unrollLoop: UnrollLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(unrollLoop: UnrollLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
@@ -165,6 +166,7 @@ abstract class AstWalker {
|
|||||||
open fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
|
open fun after(branchExpr: BranchConditionExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(unrollLoop: UnrollLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(unrollLoop: UnrollLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
@@ -510,6 +512,13 @@ abstract class AstWalker {
|
|||||||
track(after(ifExpr, parent), ifExpr, parent)
|
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) {
|
fun visit(inlineAssembly: InlineAssembly, parent: Node) {
|
||||||
track(before(inlineAssembly, parent), inlineAssembly, parent)
|
track(before(inlineAssembly, parent), inlineAssembly, parent)
|
||||||
track(after(inlineAssembly, parent), inlineAssembly, parent)
|
track(after(inlineAssembly, parent), inlineAssembly, parent)
|
||||||
|
|||||||
@@ -100,6 +100,11 @@ interface IAstVisitor {
|
|||||||
ifExpr.falsevalue.accept(this)
|
ifExpr.falsevalue.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun visit(branchExpr: BranchConditionExpression) {
|
||||||
|
branchExpr.truevalue.accept(this)
|
||||||
|
branchExpr.falsevalue.accept(this)
|
||||||
|
}
|
||||||
|
|
||||||
fun visit(label: Label) {
|
fun visit(label: Label) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -742,6 +742,12 @@ An example, to select the number of cards to use depending on what game is playe
|
|||||||
else
|
else
|
||||||
numcards = 52
|
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)
|
on .. goto / on .. call statement (jump table)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ STRUCTS and TYPED POINTERS
|
|||||||
Future Things and Ideas
|
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
|
- %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
|
- 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
|
- fix the line, cols in Position, sometimes they count from 0 sometimes from 1
|
||||||
|
|||||||
@@ -1,19 +1,42 @@
|
|||||||
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
struct Node {
|
|
||||||
ubyte id
|
|
||||||
}
|
|
||||||
|
|
||||||
^^byte @shared bptr = 2000
|
|
||||||
^^word @shared swptr = 2000
|
|
||||||
^^uword @shared uwptr = 2000
|
|
||||||
^^Node @shared node = 2000
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
alias nid = node.id
|
sys.set_carry()
|
||||||
cx16.r0 = mkword(0, cx16.r9L)
|
txt.print_ub(if_cc 0 else 1)
|
||||||
swptr^^ = mkword(0, cx16.r9L) as word
|
txt.nl()
|
||||||
uwptr^^ = mkword(0, cx16.r9L)
|
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()
|
||||||
|
; }
|
||||||
|
;}
|
||||||
|
|||||||
@@ -514,6 +514,23 @@ val OpcodesThatDependOnCarry = arrayOf(
|
|||||||
Opcode.ROXRM
|
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
|
val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThatSetStatusbitsIncludingCarry
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
|||||||
is PtPointerDeref -> false
|
is PtPointerDeref -> false
|
||||||
is PtTypeCast -> value.isSimple()
|
is PtTypeCast -> value.isSimple()
|
||||||
is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.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
|
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) {
|
class PtContainmentCheck(position: Position): PtExpression(DataType.BOOL, position) {
|
||||||
val needle: PtExpression
|
val needle: PtExpression
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
|||||||
}
|
}
|
||||||
is PtDefer -> "<defer>"
|
is PtDefer -> "<defer>"
|
||||||
is PtIfExpression -> "<ifexpr>"
|
is PtIfExpression -> "<ifexpr>"
|
||||||
|
is PtBranchCondExpression -> "<branchexpr> if_${node.condition.name.lowercase()}"
|
||||||
is PtJmpTable -> "<jmptable>"
|
is PtJmpTable -> "<jmptable>"
|
||||||
is PtStructDecl -> {
|
is PtStructDecl -> {
|
||||||
"struct ${node.name} { " + node.fields.joinToString(" ") { "${it.first} ${it.second}" } + " }"
|
"struct ${node.name} { " + node.fields.joinToString(" ") { "${it.first} ${it.second}" } + " }"
|
||||||
|
|||||||
Reference in New Issue
Block a user