fix RPN comparison exprs

This commit is contained in:
Irmen de Jong 2023-03-19 13:10:41 +01:00
parent 374464a1f8
commit df2d7d4734
9 changed files with 89 additions and 33 deletions

View File

@ -6,7 +6,7 @@ import prog8.code.core.*
* Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root), * Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root),
* passing it as a String to the specified receiver function. * passing it as a String to the specified receiver function.
*/ */
fun printAst(root: PtNode, output: (text: String) -> Unit) { fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Unit) {
fun type(dt: DataType) = "!${dt.name.lowercase()}!" fun type(dt: DataType) = "!${dt.name.lowercase()}!"
fun txt(node: PtNode): String { fun txt(node: PtNode): String {
return when(node) { return when(node) {
@ -136,16 +136,22 @@ fun printAst(root: PtNode, output: (text: String) -> Unit) {
root.children.forEach { root.children.forEach {
walkAst(it) { node, depth -> walkAst(it) { node, depth ->
val txt = txt(node) val txt = txt(node)
if(txt.isNotEmpty()) val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
output(" ".repeat(depth) + txt(node)) if(!library || !skipLibraries) {
if (txt.isNotEmpty())
output(" ".repeat(depth) + txt(node))
}
} }
} }
println() println()
} else { } else {
walkAst(root) { node, depth -> walkAst(root) { node, depth ->
val txt = txt(node) val txt = txt(node)
if(txt.isNotEmpty()) val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
output(" ".repeat(depth) + txt(node)) if(!library || !skipLibraries) {
if (txt.isNotEmpty())
output(" ".repeat(depth) + txt(node))
}
} }
} }
} }

View File

@ -26,6 +26,8 @@ class AsmGen6502: ICodeGeneratorBackend {
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY) errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
} }
// printAst(program, true) { println(it) }
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors) val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
return asmgen.compileToAssembly() return asmgen.compileToAssembly()
} }

View File

@ -102,6 +102,28 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers) RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers)
} }
} }
fun isSameAs(left: PtExpression): Boolean =
when(kind) {
TargetStorageKind.VARIABLE -> {
val scopedName: String = if('.' in asmVarname)
asmVarname
else {
val scopeName = (scope as? PtNamedNode)?.scopedName
if (scopeName == null) asmVarname else "$scopeName.$asmVarname"
}
left is PtIdentifier && left.name==scopedName
}
TargetStorageKind.ARRAY -> {
left is PtArrayIndexer && left isSameAs array!!
}
TargetStorageKind.MEMORY -> {
left isSameAs memory!!
}
TargetStorageKind.REGISTER, TargetStorageKind.STACK -> {
false
}
}
} }
internal class AsmAssignSource(val kind: SourceStorageKind, internal class AsmAssignSource(val kind: SourceStorageKind,

View File

@ -366,7 +366,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
val value = assign.source.expression as PtRpn val value = assign.source.expression as PtRpn
val (left, oper, right) = value.finalOperation() val (left, oper, right) = value.finalOperation()
// TODO RPN the fallthrough if size>3 seems to generate not 100% correct code... (balls example fills the screen weird) // TODO RPN the fallthrough if size>3 seems to generate very inefficient code...
if(value.children.size==3 && oper.operator in ComparisonOperators) { if(value.children.size==3 && oper.operator in ComparisonOperators) {
assignRPNComparison(assign, value) assignRPNComparison(assign, value)
return true return true
@ -564,20 +564,46 @@ internal class AssignmentAsmGen(private val program: PtProgram,
val rightNum = right as? PtNumber val rightNum = right as? PtNumber
val jumpIfFalseLabel = asmgen.makeLabel("cmp") val jumpIfFalseLabel = asmgen.makeLabel("cmp")
when(assign.target.datatype) { if(assign.target.isSameAs(left)) {
in ByteDatatypes -> assignConstantByte(assign.target, 0) // In-place comparison Target = Target <compare> Right
in WordDatatypes -> assignConstantWord(assign.target, 0) // NOTE : this generates pretty inefficient code.... TODO RPN optimize?
DataType.FLOAT -> assignConstantFloat(assign.target, 0.0) val targetDt = assign.target.datatype
else -> throw AssemblyError("invalid dt") val tempVar = asmgen.getTempVarName(assign.target.datatype)
val tempTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, targetDt, comparison.definingISub(), comparison.position, variableAsmName = tempVar)
when (assign.target.datatype) {
in ByteDatatypes -> assignConstantByte(tempTarget, 0)
in WordDatatypes -> assignConstantWord(tempTarget, 0)
DataType.FLOAT -> assignConstantFloat(tempTarget, 0.0)
else -> throw AssemblyError("invalid dt")
}
asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum)
when (assign.target.datatype) {
in ByteDatatypes -> assignConstantByte(tempTarget, 1)
in WordDatatypes -> assignConstantWord(tempTarget, 1)
DataType.FLOAT -> assignConstantFloat(tempTarget, 1.0)
else -> throw AssemblyError("invalid dt")
}
asmgen.out(jumpIfFalseLabel)
val tempLeft = PtIdentifier(tempVar, targetDt, comparison.position)
tempLeft.parent=comparison
asmgen.assignExpressionTo(tempLeft, assign.target)
} else {
// Normal comparison Target = Left <compare> Right
when (assign.target.datatype) {
in ByteDatatypes -> assignConstantByte(assign.target, 0)
in WordDatatypes -> assignConstantWord(assign.target, 0)
DataType.FLOAT -> assignConstantFloat(assign.target, 0.0)
else -> throw AssemblyError("invalid dt")
}
asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum)
when (assign.target.datatype) {
in ByteDatatypes -> assignConstantByte(assign.target, 1)
in WordDatatypes -> assignConstantWord(assign.target, 1)
DataType.FLOAT -> assignConstantFloat(assign.target, 1.0)
else -> throw AssemblyError("invalid dt")
}
asmgen.out(jumpIfFalseLabel)
} }
asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum)
when(assign.target.datatype) {
in ByteDatatypes -> assignConstantByte(assign.target, 1)
in WordDatatypes -> assignConstantWord(assign.target, 1)
DataType.FLOAT -> assignConstantFloat(assign.target, 1.0)
else -> throw AssemblyError("invalid dt")
}
asmgen.out(jumpIfFalseLabel)
} }
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {

View File

@ -120,7 +120,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
// println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************") // println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************")
// printProgram(program) // printProgram(program)
// println("*********** AST RIGHT BEFORE ASM GENERATION *************") // println("*********** AST RIGHT BEFORE ASM GENERATION *************")
// printAst(intermediateAst, ::println) // printAst(intermediateAst, true, ::println)
if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions)) { if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions)) {
System.err.println("Error in codegeneration or assembler") System.err.println("Error in codegeneration or assembler")

View File

@ -66,7 +66,7 @@ class TestIntermediateAst: FunSpec({
val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall
fcall.void shouldBe false fcall.void shouldBe false
fcall.type shouldBe DataType.UBYTE fcall.type shouldBe DataType.UBYTE
printAst(ast, ::println) printAst(ast, false, ::println)
} }
}) })

View File

@ -1,7 +1,6 @@
TODO TODO
==== ====
BRANCH: balls.p8 directions are wrong since the comparison operator fallthrough in attemptAssignOptimizedExprRPN
BRANCH: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt BRANCH: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt
BRANCH: check BinExprSplitter disablement any effect for RPN? BRANCH: check BinExprSplitter disablement any effect for RPN?
BRANCH: Implement RPN codegen for IR. BRANCH: Implement RPN codegen for IR.

View File

@ -43,7 +43,7 @@ main {
DX[lp] = true DX[lp] = true
else else
BX[lp]=BX[lp]-1 BX[lp]=BX[lp]-1
} else if DX[lp] { } else {
if (BX[lp] == txt.DEFAULT_WIDTH-1) { if (BX[lp] == txt.DEFAULT_WIDTH-1) {
BX[lp] = txt.DEFAULT_WIDTH-2 BX[lp] = txt.DEFAULT_WIDTH-2
DX[lp] = false DX[lp] = false
@ -56,7 +56,7 @@ main {
DY[lp] = true DY[lp] = true
else else
BY[lp]=BY[lp]-1 BY[lp]=BY[lp]-1
} else if DY[lp] == 1 { } else {
if (BY[lp] == txt.DEFAULT_HEIGHT-1) { if (BY[lp] == txt.DEFAULT_HEIGHT-1) {
BY[lp] = txt.DEFAULT_HEIGHT-2 BY[lp] = txt.DEFAULT_HEIGHT-2
DY[lp] = false DY[lp] = false

View File

@ -1,4 +1,5 @@
%import math %import math
%import textio
%zeropage basicsafe %zeropage basicsafe
; Note: this program is compatible with C64 and CX16. ; Note: this program is compatible with C64 and CX16.
@ -6,15 +7,15 @@
main { main {
sub start() { sub start() {
; ubyte[255] BC bool x
; bool[255] DX ubyte y
repeat 20 {
if math.rnd() & 22 { x = math.rnd() & 1
cx16.r0L++ y = ((math.rnd()&1)!=0)
txt.print_ub(x)
txt.spc()
txt.print_ub(y)
txt.nl()
} }
; BC[2] = math.rnd() & 15
; BC[3] = math.rnd() & 15
; BC[4] = math.rnd() & 15
;DX[2] = math.rnd() & 1
} }
} }