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 finalRightOperand() = children[children.size-2]
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) {

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 PtArrayIndexer -> "<arrayindexer> ${type(node.type)}"
is PtBinaryExpression -> "<expr> ${node.operator} ${type(node.type)}"
is PtRpn -> "<rpnexpr>"
is PtRpnOperator -> node.operator
is PtRpn -> "<rpnexpr> ${type(node.type)}"
is PtRpnOperator -> "${node.operator} ${type(node.type)}"
is PtBuiltinFunctionCall -> {
val str = if(node.void) "void " else ""
str + node.name + "()"

View File

@ -1023,15 +1023,14 @@ $repeatLabel lda $counterVar
|| (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
pointerOffsetExpr.children.removeLast()
pointerOffsetExpr.children.removeLast()
val truncatedExpr = pointerOffsetExpr.truncateLastOperator()
val tempvar = getTempVarName(DataType.UWORD)
assignExpressionToVariable(pointerOffsetExpr, tempvar, DataType.UWORD)
val smallExpr = PtRpn(DataType.UWORD, pointerOffsetExpr.position)
smallExpr.addRpnNode(PtIdentifier(tempvar, DataType.UWORD, pointerOffsetExpr.position))
assignExpressionToVariable(truncatedExpr, tempvar, DataType.UWORD)
val smallExpr = PtRpn(DataType.UWORD, truncatedExpr.position)
smallExpr.addRpnNode(PtIdentifier(tempvar, DataType.UWORD, truncatedExpr.position))
smallExpr.addRpnNode(rightmostOperand)
smallExpr.addRpnNode(rightmostOperator)
smallExpr.parent = pointerOffsetExpr.parent
smallExpr.parent = truncatedExpr.parent
val result = pointerViaIndexRegisterPossible(smallExpr)
require(result != null)
return result
@ -1178,11 +1177,9 @@ $repeatLabel lda $counterVar
val (leftRpn, oper, right) = expr.finalOperation()
if(oper.operator !in ComparisonOperators)
throw AssemblyError("must be comparison expression")
val left: PtExpression = if(expr.children.size>3 || leftRpn !is PtExpression) {
expr.children.removeLast()
expr.children.removeLast()
expr
} else
val left: PtExpression = if(expr.children.size>3 || leftRpn !is PtExpression)
expr.truncateLastOperator()
else
leftRpn
// 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) {
val (leftRpn, oper, right) = expr.finalOperation()
val left: PtExpression = if(expr.children.size>3 || leftRpn !is PtExpression) {
expr.children.removeLast()
expr.children.removeLast()
expr
} else
val left: PtExpression = if(expr.children.size>3 || leftRpn !is PtExpression)
expr.truncateLastOperator()
else
leftRpn
require(right is PtExpression)
@ -3210,6 +3205,7 @@ internal class SubroutineExtraAsmInfo {
var usedRegsaveY = false
var usedFloatEvalResultVar1 = false
var usedFloatEvalResultVar2 = false
var rpnDepth = 0 // 'depth' tracking of the RPN expression evaluator
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)
}
is PtRpnOperator -> {
expr.children.removeLast()
expr.children.removeLast()
translateComparisonWithZero(expr, leftDt, oper.operator)
val truncated = expr.truncateLastOperator()
translateComparisonWithZero(truncated, leftDt, oper.operator)
}
else -> throw AssemblyError("weird rpn node")
}
@ -282,7 +281,8 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|| (leftDt in WordDatatypes && rightDt !in WordDatatypes))
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 {
if(it is PtRpnOperator) {
when(it.leftType) {
@ -297,13 +297,13 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
}
else -> throw AssemblyError("non-numerical datatype ${it.leftType}")
}
depth--
asmExtra.rpnDepth--
} else {
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) {

View File

@ -365,6 +365,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
private fun attemptAssignOptimizedExprRPN(assign: AsmAssignment, scope: IPtSubroutine): Boolean {
val value = assign.source.expression as PtRpn
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) {
assignRPNComparison(assign, value)
@ -420,17 +422,15 @@ internal class AssignmentAsmGen(private val program: PtProgram,
return name
}
asmgen.out(" ; rpn expression @ ${value.position} ${value.children.size} nodes") // TODO
var depth=0
val startDepth = asmExtra.rpnDepth
value.children.forEach {
when (it) {
is PtRpnOperator -> {
asmgen.out(" ; rpn child node ${it.operator}") // TODO
val rightvar = evalVars.getValue(getVarDt(it.rightType)).pop()
val leftvar = evalVars.getValue(getVarDt(it.leftType)).pop()
depth-=2
val resultVarname = evalVarName(it.type, depth)
depth++
asmExtra.rpnDepth -= 2
val resultVarname = evalVarName(it.type, asmExtra.rpnDepth)
asmExtra.rpnDepth++
symbolTable.resetCachedFlat()
if(it.operator in ComparisonOperators) {
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)
assignRPNComparison(normalAssign, comparison)
} else {
require(resultVarname==leftvar) {
"expected result $resultVarname == leftvar $leftvar"
if(leftvar!=resultVarname) {
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 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 -> {
asmgen.out(" ; rpn child node expr ${it}") // TODO
val varname = evalVarName(it.type, depth)
val varname = evalVarName(it.type, asmExtra.rpnDepth)
assignExpressionToVariable(it, varname, it.type)
depth++
asmExtra.rpnDepth++
}
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()
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
// any other type difference is an error
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")
}
}
asmgen.out(" ; DONE assign rpn result to target") // TODO
require(evalVars.all { it.value.isEmpty() }) { "invalid rpn evaluation" }
return true
@ -575,11 +576,9 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
}
val left: PtExpression = if(comparison.children.size>3 || leftRpn !is PtExpression) {
comparison.children.removeLast()
comparison.children.removeLast()
comparison
} else
val left: PtExpression = if(comparison.children.size>3 || leftRpn !is PtExpression)
comparison.truncateLastOperator()
else
leftRpn
val leftNum = left as? PtNumber
@ -1011,11 +1010,9 @@ internal class AssignmentAsmGen(private val program: PtProgram,
private fun attemptAssignToByteCompareZeroRPN(expr: PtRpn, assign: AsmAssignment): Boolean {
val (leftRpn, oper, right) = expr.finalOperation()
val left = if(expr.children.size!=3 || leftRpn !is PtExpression) {
expr.children.removeLast()
expr.children.removeLast()
expr
} else
val left = if(expr.children.size!=3 || leftRpn !is PtExpression)
expr.truncateLastOperator()
else
leftRpn
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)
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)
return noModifications

View File

@ -1,15 +1,13 @@
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: check BinExprSplitter disablement any effect for RPN?
then:
RPN: examples/bsieve,charset compilation crash (bit shift expression)
RPN: cube3d-float is massive and slow
RPN: mandelbrot is big, but seems faster
RPN: swirl is MUCH slower, wizzine is slower
then:
RPN: check BinExprSplitter disablement any effect for RPN?
RPN: Implement RPN codegen for IR.

View File

@ -1,37 +1,54 @@
%import textio
%import floats
%zeropage basicsafe
main {
const ubyte numCellsHoriz = 15 ;(screenwidth-1) / 2
const ubyte numCellsVert = 7 ; (screenheight-1) / 2
; 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
}
const uword width = 256
const uword height = 240
const ubyte max_iter = 16 ; 32 actually looks pretty nice but takes longer
sub start() {
generate()
txt.nl()
txt.nl()
void cx16.screen_mode($80, false)
cx16.r0=0
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)
}
}
}
}