fix rpn variable depth clobber and type error

This commit is contained in:
Irmen de Jong 2023-03-20 21:43:53 +01:00
parent b40e397b28
commit d265271148
8 changed files with 103 additions and 86 deletions

View File

@ -270,6 +270,17 @@ class PtRpn(type: DataType, position: Position): PtExpression(type, position) {
fun finalLeftOperand() = children[children.size-3] fun finalLeftOperand() = children[children.size-3]
fun finalRightOperand() = children[children.size-2] fun finalRightOperand() = children[children.size-2]
fun finalOperation() = Triple(finalLeftOperand(), finalOperator(), finalRightOperand()) fun finalOperation() = Triple(finalLeftOperand(), finalOperator(), finalRightOperand())
fun truncateLastOperator(): PtRpn {
// NOTE: this is a destructive operation!
children.removeLast()
children.removeLast()
val finalOper = finalOperator()
if(finalOper.type==type) return this
val typeAdjusted = PtRpn(finalOper.type, this.position)
typeAdjusted.children.addAll(children)
typeAdjusted.parent = parent
return typeAdjusted
}
} }
class PtRpnOperator(val operator: String, val type: DataType, val leftType: DataType, val rightType: DataType, position: Position): PtNode(position) { class PtRpnOperator(val operator: String, val type: DataType, val leftType: DataType, val rightType: DataType, position: Position): PtNode(position) {

View File

@ -19,8 +19,8 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
is PtArray -> "array len=${node.children.size} ${type(node.type)}" is PtArray -> "array len=${node.children.size} ${type(node.type)}"
is PtArrayIndexer -> "<arrayindexer> ${type(node.type)}" is PtArrayIndexer -> "<arrayindexer> ${type(node.type)}"
is PtBinaryExpression -> "<expr> ${node.operator} ${type(node.type)}" is PtBinaryExpression -> "<expr> ${node.operator} ${type(node.type)}"
is PtRpn -> "<rpnexpr>" is PtRpn -> "<rpnexpr> ${type(node.type)}"
is PtRpnOperator -> node.operator is PtRpnOperator -> "${node.operator} ${type(node.type)}"
is PtBuiltinFunctionCall -> { is PtBuiltinFunctionCall -> {
val str = if(node.void) "void " else "" val str = if(node.void) "void " else ""
str + node.name + "()" str + node.name + "()"

View File

@ -1023,15 +1023,14 @@ $repeatLabel lda $counterVar
|| (rightmostOperand is PtTypeCast && rightmostOperand.value.type == DataType.UBYTE) || (rightmostOperand is PtTypeCast && rightmostOperand.value.type == DataType.UBYTE)
) { ) {
// split up the big expression in 2 parts so that we CAN use ZP,Y indexing after all // split up the big expression in 2 parts so that we CAN use ZP,Y indexing after all
pointerOffsetExpr.children.removeLast() val truncatedExpr = pointerOffsetExpr.truncateLastOperator()
pointerOffsetExpr.children.removeLast()
val tempvar = getTempVarName(DataType.UWORD) val tempvar = getTempVarName(DataType.UWORD)
assignExpressionToVariable(pointerOffsetExpr, tempvar, DataType.UWORD) assignExpressionToVariable(truncatedExpr, tempvar, DataType.UWORD)
val smallExpr = PtRpn(DataType.UWORD, pointerOffsetExpr.position) val smallExpr = PtRpn(DataType.UWORD, truncatedExpr.position)
smallExpr.addRpnNode(PtIdentifier(tempvar, DataType.UWORD, pointerOffsetExpr.position)) smallExpr.addRpnNode(PtIdentifier(tempvar, DataType.UWORD, truncatedExpr.position))
smallExpr.addRpnNode(rightmostOperand) smallExpr.addRpnNode(rightmostOperand)
smallExpr.addRpnNode(rightmostOperator) smallExpr.addRpnNode(rightmostOperator)
smallExpr.parent = pointerOffsetExpr.parent smallExpr.parent = truncatedExpr.parent
val result = pointerViaIndexRegisterPossible(smallExpr) val result = pointerViaIndexRegisterPossible(smallExpr)
require(result != null) require(result != null)
return result return result
@ -1178,11 +1177,9 @@ $repeatLabel lda $counterVar
val (leftRpn, oper, right) = expr.finalOperation() val (leftRpn, oper, right) = expr.finalOperation()
if(oper.operator !in ComparisonOperators) if(oper.operator !in ComparisonOperators)
throw AssemblyError("must be comparison expression") throw AssemblyError("must be comparison expression")
val left: PtExpression = if(expr.children.size>3 || leftRpn !is PtExpression) { val left: PtExpression = if(expr.children.size>3 || leftRpn !is PtExpression)
expr.children.removeLast() expr.truncateLastOperator()
expr.children.removeLast() else
expr
} else
leftRpn leftRpn
// invert the comparison, so we can reuse the JumpIfFalse code generation routines // invert the comparison, so we can reuse the JumpIfFalse code generation routines
@ -1208,11 +1205,9 @@ $repeatLabel lda $counterVar
private fun translateCompareAndJumpIfFalseRPN(expr: PtRpn, jumpIfFalseLabel: String) { private fun translateCompareAndJumpIfFalseRPN(expr: PtRpn, jumpIfFalseLabel: String) {
val (leftRpn, oper, right) = expr.finalOperation() val (leftRpn, oper, right) = expr.finalOperation()
val left: PtExpression = if(expr.children.size>3 || leftRpn !is PtExpression) { val left: PtExpression = if(expr.children.size>3 || leftRpn !is PtExpression)
expr.children.removeLast() expr.truncateLastOperator()
expr.children.removeLast() else
expr
} else
leftRpn leftRpn
require(right is PtExpression) require(right is PtExpression)
@ -3210,6 +3205,7 @@ internal class SubroutineExtraAsmInfo {
var usedRegsaveY = false var usedRegsaveY = false
var usedFloatEvalResultVar1 = false var usedFloatEvalResultVar1 = false
var usedFloatEvalResultVar2 = false var usedFloatEvalResultVar2 = false
var rpnDepth = 0 // 'depth' tracking of the RPN expression evaluator
val extraVars = mutableListOf<Triple<DataType, String, UInt?>>() val extraVars = mutableListOf<Triple<DataType, String, UInt?>>()
} }

View File

@ -263,9 +263,8 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
translateComparisonWithZero(left, leftDt, oper.operator) translateComparisonWithZero(left, leftDt, oper.operator)
} }
is PtRpnOperator -> { is PtRpnOperator -> {
expr.children.removeLast() val truncated = expr.truncateLastOperator()
expr.children.removeLast() translateComparisonWithZero(truncated, leftDt, oper.operator)
translateComparisonWithZero(expr, leftDt, oper.operator)
} }
else -> throw AssemblyError("weird rpn node") else -> throw AssemblyError("weird rpn node")
} }
@ -282,7 +281,8 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|| (leftDt in WordDatatypes && rightDt !in WordDatatypes)) || (leftDt in WordDatatypes && rightDt !in WordDatatypes))
throw AssemblyError("operator ${oper.operator} left/right dt not identical: $leftDt $rightDt right=${expr.finalRightOperand()}") throw AssemblyError("operator ${oper.operator} left/right dt not identical: $leftDt $rightDt right=${expr.finalRightOperand()}")
var depth=0 val asmExtra = asmgen.subroutineExtra(expr.definingISub()!!)
val startDepth = asmExtra.rpnDepth
expr.children.forEach { expr.children.forEach {
if(it is PtRpnOperator) { if(it is PtRpnOperator) {
when(it.leftType) { when(it.leftType) {
@ -297,13 +297,13 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
} }
else -> throw AssemblyError("non-numerical datatype ${it.leftType}") else -> throw AssemblyError("non-numerical datatype ${it.leftType}")
} }
depth-- asmExtra.rpnDepth--
} else { } else {
translateExpressionInternal(it as PtExpression) translateExpressionInternal(it as PtExpression)
depth++ asmExtra.rpnDepth++
} }
} }
require(depth==1) { "unbalanced RPN: $depth ${expr.position}" } require(asmExtra.rpnDepth-startDepth==1) { "unbalanced RPN: ${expr.position}" }
} }
private fun translateExpression(expr: PtBinaryExpression) { private fun translateExpression(expr: PtBinaryExpression) {

View File

@ -365,6 +365,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
private fun attemptAssignOptimizedExprRPN(assign: AsmAssignment, scope: IPtSubroutine): Boolean { private fun attemptAssignOptimizedExprRPN(assign: AsmAssignment, scope: IPtSubroutine): Boolean {
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()
if(oper.type != value.type)
throw AssemblyError("rpn node type error, expected ${value.type} got ${oper.type}")
if(oper.operator in ComparisonOperators) { if(oper.operator in ComparisonOperators) {
assignRPNComparison(assign, value) assignRPNComparison(assign, value)
@ -420,17 +422,15 @@ internal class AssignmentAsmGen(private val program: PtProgram,
return name return name
} }
asmgen.out(" ; rpn expression @ ${value.position} ${value.children.size} nodes") // TODO val startDepth = asmExtra.rpnDepth
var depth=0
value.children.forEach { value.children.forEach {
when (it) { when (it) {
is PtRpnOperator -> { is PtRpnOperator -> {
asmgen.out(" ; rpn child node ${it.operator}") // TODO
val rightvar = evalVars.getValue(getVarDt(it.rightType)).pop() val rightvar = evalVars.getValue(getVarDt(it.rightType)).pop()
val leftvar = evalVars.getValue(getVarDt(it.leftType)).pop() val leftvar = evalVars.getValue(getVarDt(it.leftType)).pop()
depth-=2 asmExtra.rpnDepth -= 2
val resultVarname = evalVarName(it.type, depth) val resultVarname = evalVarName(it.type, asmExtra.rpnDepth)
depth++ asmExtra.rpnDepth++
symbolTable.resetCachedFlat() symbolTable.resetCachedFlat()
if(it.operator in ComparisonOperators) { if(it.operator in ComparisonOperators) {
require(it.type == DataType.UBYTE) require(it.type == DataType.UBYTE)
@ -445,8 +445,11 @@ internal class AssignmentAsmGen(private val program: PtProgram,
val normalAssign = AsmAssignment(src, target, program.memsizer, assign.position) val normalAssign = AsmAssignment(src, target, program.memsizer, assign.position)
assignRPNComparison(normalAssign, comparison) assignRPNComparison(normalAssign, comparison)
} else { } else {
require(resultVarname==leftvar) { if(leftvar!=resultVarname) {
"expected result $resultVarname == leftvar $leftvar" val scopeName = (scope as PtNamedNode).scopedName
val leftVarPt = PtIdentifier("$scopeName.$leftvar", it.leftType, it.position)
leftVarPt.parent=scope
assignExpressionToVariable(leftVarPt, resultVarname, it.type)
} }
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, it.rightType, variableAsmName = rightvar) val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, it.rightType, variableAsmName = rightvar)
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, it.type, scope, assign.position, variableAsmName = resultVarname) val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, it.type, scope, assign.position, variableAsmName = resultVarname)
@ -455,20 +458,20 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
} }
is PtExpression -> { is PtExpression -> {
asmgen.out(" ; rpn child node expr ${it}") // TODO val varname = evalVarName(it.type, asmExtra.rpnDepth)
val varname = evalVarName(it.type, depth)
assignExpressionToVariable(it, varname, it.type) assignExpressionToVariable(it, varname, it.type)
depth++ asmExtra.rpnDepth++
} }
else -> throw AssemblyError("weird rpn node") else -> throw AssemblyError("weird rpn node")
} }
} }
asmgen.out(" ; DONE rpn expression @ ${value.position}") // TODO require(asmExtra.rpnDepth-startDepth == 1) {
"unbalanced RPN ${value.position}"
}
require(depth==1) { "unbalanced RPN: $depth ${value.position}" }
asmgen.out(" ; assign rpn result to target") // TODO
val resultVariable = evalVars.getValue(getVarDt(value.type)).pop() val resultVariable = evalVars.getValue(getVarDt(value.type)).pop()
if(assign.target.datatype != value.type) { asmExtra.rpnDepth--
if(!(assign.target.datatype equalsSize value.type)) {
// we only allow for transparent byte -> word / ubyte -> uword assignments // we only allow for transparent byte -> word / ubyte -> uword assignments
// any other type difference is an error // any other type difference is an error
if(assign.target.datatype in WordDatatypes && value.type in ByteDatatypes) { if(assign.target.datatype in WordDatatypes && value.type in ByteDatatypes) {
@ -486,8 +489,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
else -> throw AssemblyError("weird dt") else -> throw AssemblyError("weird dt")
} }
} }
asmgen.out(" ; DONE assign rpn result to target") // TODO
require(evalVars.all { it.value.isEmpty() }) { "invalid rpn evaluation" } require(evalVars.all { it.value.isEmpty() }) { "invalid rpn evaluation" }
return true return true
@ -575,11 +576,9 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
} }
val left: PtExpression = if(comparison.children.size>3 || leftRpn !is PtExpression) { val left: PtExpression = if(comparison.children.size>3 || leftRpn !is PtExpression)
comparison.children.removeLast() comparison.truncateLastOperator()
comparison.children.removeLast() else
comparison
} else
leftRpn leftRpn
val leftNum = left as? PtNumber val leftNum = left as? PtNumber
@ -1011,11 +1010,9 @@ internal class AssignmentAsmGen(private val program: PtProgram,
private fun attemptAssignToByteCompareZeroRPN(expr: PtRpn, assign: AsmAssignment): Boolean { private fun attemptAssignToByteCompareZeroRPN(expr: PtRpn, assign: AsmAssignment): Boolean {
val (leftRpn, oper, right) = expr.finalOperation() val (leftRpn, oper, right) = expr.finalOperation()
val left = if(expr.children.size!=3 || leftRpn !is PtExpression) { val left = if(expr.children.size!=3 || leftRpn !is PtExpression)
expr.children.removeLast() expr.truncateLastOperator()
expr.children.removeLast() else
expr
} else
leftRpn leftRpn
when (oper.operator) { when (oper.operator) {
"==" -> { "==" -> {

View File

@ -21,8 +21,6 @@ class BinExprSplitter(private val program: Program, private val options: Compila
if(options.compTarget.name == VMTarget.NAME) if(options.compTarget.name == VMTarget.NAME)
return noModifications // don't split expressions when targeting the vm codegen, it handles nested expressions well return noModifications // don't split expressions when targeting the vm codegen, it handles nested expressions well
if(options.useRPN) // TODO RPN does this make a difference?
return noModifications
if(assignment.value.inferType(program) istype DataType.FLOAT && !options.optimizeFloatExpressions) if(assignment.value.inferType(program) istype DataType.FLOAT && !options.optimizeFloatExpressions)
return noModifications return noModifications

View File

@ -1,15 +1,13 @@
TODO TODO
==== ====
RPN: examples/maze crashes RPN: cx16/mandelbrot-gfx-colors half display is wrong
RPN: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt RPN: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt
RPN: check BinExprSplitter disablement any effect for RPN?
then: then:
RPN: examples/bsieve,charset compilation crash (bit shift expression) RPN: examples/bsieve,charset compilation crash (bit shift expression)
RPN: cube3d-float is massive and slow RPN: cube3d-float is massive and slow
RPN: mandelbrot is big, but seems faster RPN: mandelbrot is big, but seems faster
RPN: swirl is MUCH slower, wizzine is slower RPN: swirl is MUCH slower, wizzine is slower
then: then:
RPN: check BinExprSplitter disablement any effect for RPN?
RPN: Implement RPN codegen for IR. RPN: Implement RPN codegen for IR.

View File

@ -1,37 +1,54 @@
%import textio %import textio
%import floats
%zeropage basicsafe %zeropage basicsafe
main { main {
const ubyte numCellsHoriz = 15 ;(screenwidth-1) / 2 const uword width = 256
const ubyte numCellsVert = 7 ; (screenheight-1) / 2 const uword height = 240
const ubyte max_iter = 16 ; 32 actually looks pretty nice but takes longer
; cell properties
const ubyte RIGHT = 2
ubyte[256] cells = 0
sub generate() {
ubyte cx = 0
cells[0] = 255
repeat 40 {
bool fits = cx<numCellsHoriz
if fits and not @(celladdr(cx+1)) { ; TODO evaluated wrong in RPN! Only as part of IF, and using celladdr()
cx++
cells[cx] = 255
}
}
txt.print_ub(cx)
txt.print(" should be ")
txt.print_ub(numCellsHoriz)
}
sub celladdr(ubyte cx) -> uword {
return &cells+cx
}
sub start() { sub start() {
generate() void cx16.screen_mode($80, false)
txt.nl() cx16.r0=0
txt.nl() cx16.FB_init()
mandel()
}
sub mandel() {
const float XL=-2.200
const float XU=0.800
const float YL=-1.300
const float YU=1.300
float dx = (XU-XL)/width
float dy = (YU-YL)/height
ubyte pixelx
ubyte pixely
for pixely in 0 to height-1 {
float yy = YL+dy*(pixely as float)
cx16.FB_cursor_position(0, pixely)
for pixelx in 0 to width-1 {
float xx = XL+dx*(pixelx as float)
float xsquared = 0.0
float ysquared = 0.0
float x = 0.0
float y = 0.0
ubyte iter = 0
while xsquared+ysquared<4.0 {
y = x*y*2.0 + yy
x = xsquared - ysquared + xx
xsquared = x*x
ysquared = y*y
iter++
if iter>16
break
}
cx16.FB_set_pixel(iter)
}
}
} }
} }