got rid of rpn deadend code...

This commit is contained in:
Irmen de Jong 2023-03-25 18:45:17 +01:00
parent ca2af2ca63
commit 629ed74d09
23 changed files with 60 additions and 874 deletions

View File

@ -53,8 +53,7 @@ sealed class PtNamedNode(var name: String, position: Position): PtNode(position)
class PtProgram(
val name: String,
val memsizer: IMemSizer,
val encoding: IStringEncoding,
var binaryExpressionsAreRPN: Boolean = false
val encoding: IStringEncoding
) : PtNode(Position.DUMMY) {
// fun allModuleDirectives(): Sequence<PtDirective> =
@ -65,53 +64,6 @@ class PtProgram(
fun entrypoint(): PtSub? =
allBlocks().firstOrNull { it.name == "main" }?.children?.firstOrNull { it is PtSub && it.name == "start" } as PtSub?
// If the code generator wants, it can transform binary expression nodes into flat RPN nodes.
// This will destroy the original binaryexpression nodes!
fun transformBinExprToRPN() {
if(binaryExpressionsAreRPN)
return
fun transformToRPN(originalExpr: PtBinaryExpression): PtRpn {
fun makeRpn(expr: PtExpression): PtRpn {
val rpn = PtRpn(expr.type, expr.position)
if(expr is PtBinaryExpression)
rpn.addRpnNode(transformToRPN(expr))
else
rpn.addRpnNode(expr)
return rpn
}
val rpn = PtRpn(originalExpr.type, originalExpr.position)
rpn.addRpnNode(makeRpn(originalExpr.left))
rpn.addRpnNode(makeRpn(originalExpr.right))
rpn.addRpnNode(PtRpnOperator(originalExpr.operator, originalExpr.type, originalExpr.left.type, originalExpr.right.type, originalExpr.position))
return rpn
}
fun transformBinExprToRPN(node: PtNode, parent: PtNode) {
if(node is PtBinaryExpression) {
val rpn = transformToRPN(node)
val idx = parent.children.indexOf(node)
rpn.parent = parent
parent.children[idx] = rpn
}
node.children.forEach {child ->
transformBinExprToRPN(child, node)
}
}
children.forEach { transformBinExprToRPN(it, this) }
binaryExpressionsAreRPN = true
// extra check to see that all PtBinaryExpressions have been transformed
fun binExprCheck(node: PtNode) {
if(node is PtBinaryExpression)
throw IllegalArgumentException("still got binexpr $node ${node.position}")
node.children.forEach { binExprCheck(it) }
}
binExprCheck(this)
}
}

View File

@ -3,7 +3,6 @@ package prog8.code.ast
import prog8.code.core.*
import java.util.*
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.round
@ -28,7 +27,6 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index
is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right
is PtRpn -> other is PtRpn && this.isSame(other)
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
is PtIdentifier -> other is PtIdentifier && other.type==type && other.name==name
is PtMachineRegister -> other is PtMachineRegister && other.type==type && other.register==register
@ -64,7 +62,6 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
is PtArray -> true
is PtArrayIndexer -> index is PtNumber || index is PtIdentifier
is PtBinaryExpression -> false
is PtRpn -> false
is PtBuiltinFunctionCall -> name in arrayOf("msb", "lsb", "peek", "peekw", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd")
is PtContainmentCheck -> false
is PtFunctionCall -> false
@ -161,146 +158,6 @@ class PtBinaryExpression(val operator: String, type: DataType, position: Positio
}
class PtRpn(type: DataType, position: Position): PtExpression(type, position) {
// contains only PtExpression (not PtRpn!) and PtRpnOperator nodes
// not created directly by the compiler for now, if code generators prefer this over PtBinaryExpression,
// they have to transform the ast themselves first using the utility routine on PtProgram for it.
fun addRpnNode(node: PtNode) {
require(node is PtRpnOperator || node is PtExpression)
if(node is PtRpn) {
node.children.forEach {
children.add(it)
it.parent = this
}
}
else {
require(node !is PtBinaryExpression)
children.add(node)
node.parent = this
}
}
fun print() {
children.forEach {
when(it) {
is PtRpnOperator -> println(it.operator)
is PtExpression -> println("expr $it ${it.position}")
else -> {}
}
}
}
fun isSame(other: PtRpn): Boolean {
if(other.children.size==children.size) {
return other.children.zip(this.children).all { (first, second) ->
when (first) {
is PtRpnOperator -> second is PtRpnOperator && first.operator==second.operator
is PtExpression -> second is PtExpression && first isSameAs second
else -> false
}
}
}
return false
}
fun maxDepth(): Map<DataType, Int> {
val depths = mutableMapOf(
DataType.UBYTE to 0,
DataType.UWORD to 0,
DataType.FLOAT to 0
)
val maxDepths = mutableMapOf(
DataType.UBYTE to 0,
DataType.UWORD to 0,
DataType.FLOAT to 0
)
var numPushes = 0
var numPops = 0
fun push(type: DataType) {
when (type) {
in ByteDatatypes -> {
val depth = depths.getValue(DataType.UBYTE) + 1
depths[DataType.UBYTE] = depth
maxDepths[DataType.UBYTE] = max(maxDepths.getValue(DataType.UBYTE), depth)
}
in WordDatatypes, in PassByReferenceDatatypes -> {
val depth = depths.getValue(DataType.UWORD) + 1
depths[DataType.UWORD] = depth
maxDepths[DataType.UWORD] = max(maxDepths.getValue(DataType.UWORD), depth)
}
DataType.FLOAT -> {
val depth = depths.getValue(DataType.FLOAT) + 1
depths[DataType.FLOAT] = depth
maxDepths[DataType.FLOAT] = max(maxDepths.getValue(DataType.FLOAT), depth)
}
else -> throw IllegalArgumentException("invalid dt")
}
numPushes++
}
fun pop(type: DataType) {
when (type) {
in ByteDatatypes -> depths[DataType.UBYTE]=depths.getValue(DataType.UBYTE) - 1
in WordDatatypes, in PassByReferenceDatatypes -> depths[DataType.UWORD]=depths.getValue(DataType.UWORD) - 1
DataType.FLOAT -> depths[DataType.FLOAT]=depths.getValue(DataType.FLOAT) - 1
else -> throw IllegalArgumentException("invalid dt")
}
numPops++
}
children.withIndex().forEach { (index, node) ->
if (node is PtRpnOperator) {
pop(node.leftType)
pop(node.rightType)
push(node.type)
}
else {
push((node as PtExpression).type)
}
}
require(numPushes==numPops+1 && numPushes==children.size) {
"RPN not balanced, pushes=$numPushes pops=$numPops childs=${children.size}"
}
return maxDepths
}
fun finalOperator() = children.last() as PtRpnOperator
fun finalLeftOperand() = children[children.size-3]
fun finalRightOperand() = children[children.size-2]
fun finalOperation() = Triple(finalLeftOperand(), finalOperator(), finalRightOperand())
fun truncateLastOperator(): PtExpression {
// NOTE: this is a destructive operation!
children.removeLast()
children.removeLast()
if(children.last() !is PtRpnOperator) {
if(children.size==1 && children[0] is PtExpression)
return children[0] as PtExpression
else
throw IllegalArgumentException("don't know what to do with children: $children")
}
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) {
init {
// NOTE: For now, we require that the types of the operands are the same size as the output type of the operator node.
if(operator !in ComparisonOperators && operator != "<<" && operator != ">>") {
require(type equalsSize leftType && type equalsSize rightType) {
"operand type size(s) differ from operator result type $type: $leftType $rightType oper: $operator"
}
}
}
}
class PtContainmentCheck(position: Position): PtExpression(DataType.UBYTE, position) {
val element: PtExpression
get() = children[0] as PtExpression

View File

@ -19,8 +19,6 @@ 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> ${type(node.type)}"
is PtRpnOperator -> "${node.operator} ${type(node.type)}"
is PtBuiltinFunctionCall -> {
val str = if(node.void) "void " else ""
str + node.name + "()"

View File

@ -20,7 +20,7 @@ class CompilationOptions(val output: OutputType,
var asmListfile: Boolean = false,
var experimentalCodegen: Boolean = false,
var varsHigh: Boolean = false,
var useRPN: Boolean = false,
var useNewExprCode: Boolean = false,
var evalStackBaseAddress: UInt? = null,
var outputDir: Path = Path(""),
var symbolDefs: Map<String, String> = emptyMap()

View File

@ -21,9 +21,9 @@ class AsmGen6502: ICodeGeneratorBackend {
options: CompilationOptions,
errors: IErrorReporter
): IAssemblyProgram? {
if(options.useRPN) {
program.transformBinExprToRPN()
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
if(options.useNewExprCode) {
// TODO("transform BinExprs?")
// errors.warn("EXPERIMENTAL NEW EXPRESSION CODEGEN IS USED. CODE SIZE+SPEED POSSIBLY SUFFERS.", Position.DUMMY)
}
// printAst(program, true) { println(it) }
@ -551,59 +551,33 @@ class AsmGen6502Internal (
}
private fun translate(stmt: PtIfElse) {
if(stmt.condition is PtRpn) {
val condition = stmt.condition as PtRpn
requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>'
if (stmt.elseScope.children.isEmpty()) {
val jump = stmt.ifScope.children.singleOrNull()
if (jump is PtJump) {
translateCompareAndJumpIfTrueRPN(condition, jump)
} else {
val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalseRPN(condition, endLabel)
translate(stmt.ifScope)
out(endLabel)
}
val condition = stmt.condition as PtBinaryExpression
requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>'
if (stmt.elseScope.children.isEmpty()) {
val jump = stmt.ifScope.children.singleOrNull()
if (jump is PtJump) {
translateCompareAndJumpIfTrue(condition, jump)
} else {
// both true and else parts
val elseLabel = makeLabel("if_else")
val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalseRPN(condition, elseLabel)
translateCompareAndJumpIfFalse(condition, endLabel)
translate(stmt.ifScope)
jmp(endLabel)
out(elseLabel)
translate(stmt.elseScope)
out(endLabel)
}
} else {
val condition = stmt.condition as PtBinaryExpression
requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>'
if (stmt.elseScope.children.isEmpty()) {
val jump = stmt.ifScope.children.singleOrNull()
if (jump is PtJump) {
translateCompareAndJumpIfTrue(condition, jump)
} else {
val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalse(condition, endLabel)
translate(stmt.ifScope)
out(endLabel)
}
} else {
// both true and else parts
val elseLabel = makeLabel("if_else")
val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalse(condition, elseLabel)
translate(stmt.ifScope)
jmp(endLabel)
out(elseLabel)
translate(stmt.elseScope)
out(endLabel)
}
// both true and else parts
val elseLabel = makeLabel("if_else")
val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalse(condition, elseLabel)
translate(stmt.ifScope)
jmp(endLabel)
out(elseLabel)
translate(stmt.elseScope)
out(endLabel)
}
}
private fun requireComparisonExpression(condition: PtExpression) {
if (!(condition is PtRpn && condition.finalOperator().operator in ComparisonOperators) && !(condition is PtBinaryExpression && condition.operator in ComparisonOperators))
if (!(condition is PtBinaryExpression && condition.operator in ComparisonOperators))
throw AssemblyError("expected boolean comparison expression $condition")
}
@ -766,7 +740,7 @@ $repeatLabel lda $counterVar
}
val isNested = parent is PtRepeatLoop
if(!isNested && !options.useRPN) {
if(!isNested && !options.useNewExprCode) {
// we can re-use a counter var from the subroutine if it already has one for that datatype
val existingVar = asmInfo.extraVars.firstOrNull { it.first==dt && it.second.endsWith("counter") }
if(existingVar!=null) {
@ -1012,45 +986,12 @@ $repeatLabel lda $counterVar
val right: PtExpression
val operator: String
when (pointerOffsetExpr) {
is PtRpn -> {
if(pointerOffsetExpr.children.size>3) {
val rightmostOperator = pointerOffsetExpr.finalOperator()
if(rightmostOperator.operator=="+") {
val rightmostOperand = pointerOffsetExpr.finalRightOperand()
if ((rightmostOperand is PtNumber && rightmostOperand.type in IntegerDatatypes && rightmostOperand.number.toInt() in 0..255)
|| (rightmostOperand is PtExpression && rightmostOperand.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
val truncatedExpr = pointerOffsetExpr.truncateLastOperator()
val tempvar = getTempVarName(DataType.UWORD)
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 = truncatedExpr.parent
val result = pointerViaIndexRegisterPossible(smallExpr)
require(result != null)
return result
}
}
return null // expression is too complex
}
val (leftNode, oper, rightNode) = pointerOffsetExpr.finalOperation()
operator=oper.operator
if (leftNode !is PtExpression || rightNode !is PtExpression) return null
left = leftNode
right = rightNode
}
is PtBinaryExpression -> {
operator = pointerOffsetExpr.operator
left = pointerOffsetExpr.left
right = pointerOffsetExpr.right
}
else -> return null
if (pointerOffsetExpr is PtBinaryExpression) {
operator = pointerOffsetExpr.operator
left = pointerOffsetExpr.left
right = pointerOffsetExpr.right
}
else return null
if (operator != "+") return null
val leftDt = left.type
@ -1173,53 +1114,6 @@ $repeatLabel lda $counterVar
return node.definingSub()?.parameters?.singleOrNull { it.name===name }
}
private fun translateCompareAndJumpIfTrueRPN(expr: PtRpn, jump: PtJump) {
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.truncateLastOperator()
else
leftRpn
// invert the comparison, so we can reuse the JumpIfFalse code generation routines
val invertedComparisonOperator = invertedComparisonOperator(oper.operator)
?: throw AssemblyError("can't invert comparison $expr")
val label = when {
jump.generatedLabel!=null -> jump.generatedLabel!!
jump.identifier!=null -> asmSymbolName(jump.identifier!!)
jump.address!=null -> jump.address!!.toHex()
else -> throw AssemblyError("weird jump")
}
val rightConstVal = right as? PtNumber
if (rightConstVal!=null && rightConstVal.number == 0.0) {
testZeroAndJump(left, invertedComparisonOperator, label)
}
else {
require(right is PtExpression)
val leftConstVal = left as? PtNumber
testNonzeroComparisonAndJump(left, invertedComparisonOperator, right, label, leftConstVal, rightConstVal)
}
}
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.truncateLastOperator()
else
leftRpn
require(right is PtExpression)
val leftConstVal = left as? PtNumber
val rightConstVal = right as? PtNumber
if (rightConstVal!=null && rightConstVal.number == 0.0)
testZeroAndJump(left, oper.operator, jumpIfFalseLabel)
else
testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal)
}
private fun translateCompareAndJumpIfTrue(expr: PtBinaryExpression, jump: PtJump) {
if(expr.operator !in ComparisonOperators)
throw AssemblyError("must be comparison expression")
@ -2967,15 +2861,6 @@ $repeatLabel lda $counterVar
assignViaExprEval()
}
}
is PtRpn -> {
val addrExpr = expr.address as PtRpn
if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.finalOperator().operator, false)) {
if(pushResultOnEstack)
out(" sta P8ESTACK_LO,x | dex")
} else {
assignViaExprEval()
}
}
else -> assignViaExprEval()
}
}
@ -3205,7 +3090,6 @@ 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

@ -661,7 +661,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
return
}
}
is PtRpn, is PtBinaryExpression -> {
is PtBinaryExpression -> {
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
val pointer = result?.first as? PtIdentifier
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
@ -723,7 +723,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
} else fallback()
}
is PtRpn, is PtBinaryExpression -> {
is PtBinaryExpression -> {
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
val pointer = result?.first as? PtIdentifier
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {

View File

@ -25,7 +25,6 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
when(expression) {
is PtPrefix -> translateExpression(expression)
is PtBinaryExpression -> translateExpression(expression)
is PtRpn -> translateRpnExpression(expression)
is PtArrayIndexer -> translateExpression(expression)
is PtTypeCast -> translateExpression(expression)
is PtAddressOf -> translateExpression(expression)
@ -245,70 +244,8 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
}
}
private fun translateRpnExpression(expr: PtRpn) {
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
val (left, oper, right) = expr.finalOperation()
if(left is PtExpression && right is PtExpression && translateSomewhatOptimized(left, oper.operator, right))
return
val leftDt = oper.leftType
val rightDt = oper.rightType
// comparison with zero
if(oper.operator in ComparisonOperators && leftDt in NumericDatatypes && rightDt in NumericDatatypes) {
val rightVal = (expr.finalRightOperand() as PtExpression).asConstInteger()
if (rightVal == 0) {
when (left) {
is PtExpression -> {
translateComparisonWithZero(left, leftDt, oper.operator)
}
is PtRpnOperator -> {
val truncated = expr.truncateLastOperator()
translateComparisonWithZero(truncated, leftDt, oper.operator)
}
else -> throw AssemblyError("weird rpn node")
}
return
}
}
// string compare
if(left is PtExpression && leftDt==DataType.STR && rightDt==DataType.STR && oper.operator in ComparisonOperators)
return translateCompareStrings(left, oper.operator, expr.finalRightOperand() as PtExpression)
// any other expression
if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes)
|| (leftDt in WordDatatypes && rightDt !in WordDatatypes))
throw AssemblyError("operator ${oper.operator} left/right dt not identical: $leftDt $rightDt right=${expr.finalRightOperand()}")
val asmExtra = asmgen.subroutineExtra(expr.definingISub()!!)
val startDepth = asmExtra.rpnDepth
expr.children.forEach {
if(it is PtRpnOperator) {
when(it.leftType) {
in ByteDatatypes -> translateBinaryOperatorBytes(it.operator, it.leftType)
in WordDatatypes -> translateBinaryOperatorWords(it.operator, it.leftType)
DataType.FLOAT -> translateBinaryOperatorFloats(it.operator)
DataType.STR -> {
if(it.operator !in ComparisonOperators)
throw AssemblyError("expected only comparison operators on string, not ${oper.operator}")
asmgen.out(" jsr prog8_lib.strcmp_stack")
compareStringsProcessResultInA(it.operator)
}
else -> throw AssemblyError("non-numerical datatype ${it.leftType}")
}
asmExtra.rpnDepth--
} else {
translateExpressionInternal(it as PtExpression)
asmExtra.rpnDepth++
}
}
require(asmExtra.rpnDepth-startDepth==1) { "unbalanced RPN: ${expr.position}" }
}
private fun translateExpression(expr: PtBinaryExpression) {
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
require(!program.binaryExpressionsAreRPN)
if(translateSomewhatOptimized(expr.left, expr.operator, expr.right))
return

View File

@ -146,14 +146,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
is PtIdentifier -> {
assignMemoryByte(assign.target, null, value.address as PtIdentifier)
}
is PtRpn -> {
val addrExpr = value.address as PtRpn
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.finalOperator().operator, false)) {
assignRegisterByte(assign.target, CpuRegister.A)
} else {
assignViaExprEval(value.address)
}
}
is PtBinaryExpression -> {
val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
@ -309,7 +301,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignRegisterByte(assign.target, CpuRegister.A)
}
is PtBinaryExpression -> {
require(!program.binaryExpressionsAreRPN)
if(!attemptAssignOptimizedBinexpr(value, assign)) {
// All remaining binary expressions just evaluate via the stack for now.
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,
@ -317,15 +308,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
fallbackToStackEval(assign)
}
}
is PtRpn -> {
if(!attemptAssignOptimizedExprRPN(assign, scope!!)) {
// All remaining binary expressions just evaluate via the stack for now.
// TODO: For RPN expressions this should never occur anymore and the eval stack should be removed when we achieve this
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,
// because the code here is the implementation of exactly that...)
fallbackToStackEval(assign)
}
}
else -> throw AssemblyError("weird assignment value type $value")
}
}
@ -363,234 +345,6 @@ 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(value.children.size==3 && left is PtExpression && right is PtExpression) {
// TODO re-enable after compiler errors are fixed:
// if(right.asConstInteger() == 0) {
// if(oper.operator == "==" || oper.operator=="!=") {
// when(assign.target.datatype) {
// in ByteDatatypes -> if(attemptAssignToByteCompareZeroRPN(value, assign)) return true
// else -> {
// // do nothing, this is handled by a type cast.
// }
// }
// }
// }
if(assign.target.datatype == oper.type && oper.leftType == oper.type) {
println("TODO simple augmented assign operator into target: ${assign.position} ${oper.leftType} ${oper.operator} ${oper.rightType} -> ${oper.type}")
println(" left=$left right=$right")
//augmentableAsmGen.translate()
} else {
println("TODO augmented assign operator into target but needs tempvar: ${assign.position} ${oper.leftType} ${oper.operator} ${oper.rightType} -> ${oper.type}")
println(" left=$left right=$right")
}
// if(oper.operator in ComparisonOperators) {
// println("TODO simple comparison: ${assign.position} ${oper.leftType} ${oper.operator} ${oper.rightType} -> ${oper.type}")
// }
// else if(oper.operator in setOf("&", "|", "^", "and", "or", "xor")) {
// println("TODO simple logical: ${assign.position} ${oper.leftType} ${oper.operator} ${oper.rightType} -> ${oper.type}")
// }
// else if(oper.operator=="+" || oper.operator=="-") {
// println("TODO simple plus or minus: ${assign.position} ${oper.leftType} ${oper.operator} ${oper.rightType} -> ${oper.type}")
// }
// else if(oper.operator=="<<" || oper.operator==">>") {
// println("TODO simple bitshift: ${assign.position} ${oper.leftType} ${oper.operator} ${oper.rightType} -> ${oper.type}")
// }
}
// TODO RPN optimizations for simple cases
// if(oper.operator in ComparisonOperators) {
// assignRPNComparison(assign, value)
// return true
// }
//
// if(right is PtExpression) {
// if (simpleEqualityExprRPN(value, oper, right, assign.target))
// return true
// if (simpleLogicalExprRPN(value, oper, right, assign.target))
// return true
// if (simplePlusOrMinusExprRPN(value, oper, right, assign.target))
// return true
// if (simpleBitshiftExprRPN(value, oper, right, assign.target))
// return true
// }
val asmExtra = asmgen.subroutineExtra(scope)
val evalVars = mutableMapOf (
DataType.UBYTE to Stack<String>(),
DataType.UWORD to Stack<String>(),
DataType.FLOAT to Stack<String>()
)
fun getVarDt(dt: DataType) =
when(dt) {
in ByteDatatypes -> DataType.UBYTE
in WordDatatypes, in PassByReferenceDatatypes -> DataType.UWORD
else -> dt
}
fun evalVarName(dt: DataType, depth: Int): String {
val name: String
val varDt: DataType
when(dt) {
in ByteDatatypes -> {
name = "p8_rpn_eval_byte_$depth"
varDt = DataType.UBYTE
}
in WordDatatypes, in PassByReferenceDatatypes -> {
name = "p8_rpn_eval_word_$depth"
varDt = DataType.UWORD
}
DataType.FLOAT -> {
name = "p8_rpn_eval_float_$depth"
varDt = DataType.FLOAT
}
else -> throw AssemblyError("weird dt")
}
evalVars.getValue(varDt).push(name)
if(!asmExtra.extraVars.any { it.second==name }) {
val stScope = symbolTable.lookup((scope as PtNamedNode).scopedName)!!
val dummyNode = PtVariable(name, varDt, ZeropageWish.DONTCARE, null, null, Position.DUMMY)
dummyNode.parent = scope
stScope.add(StStaticVariable(name, varDt, null, null, null, null, ZeropageWish.DONTCARE, dummyNode))
asmExtra.extraVars.add(Triple(varDt, name, null))
}
return name
}
val startDepth = asmExtra.rpnDepth
value.children.forEach {
when (it) {
is PtRpnOperator -> {
val rightvar = evalVars.getValue(getVarDt(it.rightType)).pop()
val leftvar = evalVars.getValue(getVarDt(it.leftType)).pop()
asmExtra.rpnDepth -= 2
val resultVarname = evalVarName(it.type, asmExtra.rpnDepth)
asmExtra.rpnDepth++
symbolTable.resetCachedFlat()
val scopeName = (scope as PtNamedNode).scopedName
val leftVarPt = PtIdentifier("$scopeName.$leftvar", it.leftType, it.position)
leftVarPt.parent = scope
if(it.rightType largerThan it.type) {
if(it.operator !in ComparisonOperators)
throw AssemblyError("only expected a boolean comparison, got ${it.operator}")
if(it.rightType !in WordDatatypes || it.type !in ByteDatatypes) {
when (it.rightType) {
DataType.STR -> {
val rightString = PtIdentifier("$scopeName.$rightvar", DataType.STR, it.position)
rightString.parent = scope
asmgen.assignExpressionToVariable(leftVarPt, "prog8_lib.strcmp_expression._arg_s1", DataType.UWORD)
asmgen.assignExpressionToVariable(rightString, "prog8_lib.strcmp_expression._arg_s2", DataType.UWORD)
asmgen.out(" jsr prog8_lib.strcmp_expression") // result of compare is in A
when(it.operator) {
"==" -> asmgen.out(" and #1 | eor #1")
"!=" -> asmgen.out(" and #1")
"<=" -> asmgen.out("""
bpl +
lda #1
bne ++
+ lda #0
+""")
">=" -> asmgen.out("""
bmi +
lda #1
bne ++
+ lda #0
+""")
"<" -> asmgen.out("""
bmi +
lda #0
beq ++
+ lda #1
+""")
">" -> asmgen.out("""
bpl +
lda #0
beq ++
+ lda #1
+""")
}
asmgen.out(" sta $resultVarname")
}
in NumericDatatypes -> {
val jumpIfFalseLabel = asmgen.makeLabel("cmp")
val rightVarPt = PtIdentifier("$scopeName.$rightvar", it.rightType, it.position)
rightVarPt.parent = scope
asmgen.testNonzeroComparisonAndJump(leftVarPt, it.operator, rightVarPt, jumpIfFalseLabel, null, null)
asmgen.out("""
lda #1
bne +
$jumpIfFalseLabel lda #0
+ sta $resultVarname""")
}
else -> throw AssemblyError("weird type for operator: ${it.rightType}")
}
} else {
// use in-place assignment with optional cast to the target variable
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, it.rightType, variableAsmName = rightvar)
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, it.leftType, scope, assign.position, variableAsmName = leftvar)
val operator = if(it.operator in ComparisonOperators) it.operator else it.operator+'='
val augAssign = AsmAugmentedAssignment(src, operator, target, program.memsizer, assign.position)
augmentableAsmGen.translate(augAssign, scope)
if(resultVarname!=leftvar)
assignTypeCastedIdentifier(resultVarname, it.type, leftvar, it.leftType)
}
} else {
// use in-place assignment with optional cast to the target variable
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, it.rightType, variableAsmName = rightvar)
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, it.leftType, scope, assign.position, variableAsmName = leftvar)
val operator = if(it.operator in ComparisonOperators) it.operator else it.operator+'='
val augAssign = AsmAugmentedAssignment(src, operator, target, program.memsizer, assign.position)
augmentableAsmGen.translate(augAssign, scope)
if(resultVarname!=leftvar)
assignTypeCastedIdentifier(resultVarname, it.type, leftvar, it.leftType)
}
}
is PtExpression -> {
val varname = evalVarName(it.type, asmExtra.rpnDepth)
assignExpressionToVariable(it, varname, it.type)
asmExtra.rpnDepth++
}
else -> throw AssemblyError("weird rpn node")
}
}
require(asmExtra.rpnDepth-startDepth == 1) {
"unbalanced RPN ${value.position}"
}
val resultVariable = evalVars.getValue(getVarDt(value.type)).pop()
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) {
assignVariableToRegister(resultVariable, RegisterOrPair.A, value.type==DataType.BYTE, scope, assign.position)
asmgen.signExtendAYlsb(value.type)
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
} else {
throw AssemblyError("data type mismatch, missing typecast ${value.type} -> ${assign.target.datatype}")
}
} else {
when (value.type) {
in ByteDatatypes -> assignVariableByte(assign.target, resultVariable)
in WordDatatypes -> assignVariableWord(assign.target, resultVariable)
DataType.FLOAT -> assignVariableFloat(assign.target, resultVariable)
else -> throw AssemblyError("weird dt")
}
}
require(evalVars.all { it.value.isEmpty() }) { "invalid rpn evaluation" }
return true
}
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
if(expr.operator in ComparisonOperators) {
if(expr.right.asConstInteger() == 0) {
@ -973,82 +727,6 @@ $jumpIfFalseLabel lda #0
assignRegisterpairWord(target, RegisterOrPair.AY)
}
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.truncateLastOperator()
else
leftRpn
when (oper.operator) {
"==" -> {
when(val dt = left.type) {
in ByteDatatypes -> {
assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE)
asmgen.out("""
beq +
lda #0
beq ++
+ lda #1
+""")
assignRegisterByte(assign.target, CpuRegister.A)
return true
}
in WordDatatypes -> {
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
asmgen.out("""
sty P8ZP_SCRATCH_B1
ora P8ZP_SCRATCH_B1
beq +
lda #0
beq ++
+ lda #1
+""")
assignRegisterByte(assign.target, CpuRegister.A)
return true
}
DataType.FLOAT -> {
assignExpressionToRegister(left, RegisterOrPair.FAC1, true)
asmgen.out(" jsr floats.SIGN | and #1 | eor #1")
assignRegisterByte(assign.target, CpuRegister.A)
return true
}
else->{
return false
}
}
}
"!=" -> {
when(val dt = left.type) {
in ByteDatatypes -> {
assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE)
asmgen.out(" beq + | lda #1")
asmgen.out("+")
assignRegisterByte(assign.target, CpuRegister.A)
return true
}
in WordDatatypes -> {
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
asmgen.out(" sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1")
asmgen.out(" beq + | lda #1")
asmgen.out("+")
assignRegisterByte(assign.target, CpuRegister.A)
return true
}
DataType.FLOAT -> {
assignExpressionToRegister(left, RegisterOrPair.FAC1, true)
asmgen.out(" jsr floats.SIGN")
assignRegisterByte(assign.target, CpuRegister.A)
return true
}
else->{
return false
}
}
}
else -> return false
}
}
private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
when (expr.operator) {
"==" -> {
@ -1228,15 +906,6 @@ $jumpIfFalseLabel lda #0
is PtIdentifier -> {
assignMemoryByteIntoWord(target, null, value.address as PtIdentifier)
}
is PtRpn -> {
val addrExpr = value.address as PtRpn
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.finalOperator().operator, false)) {
asmgen.out(" ldy #0")
assignRegisterpairWord(target, RegisterOrPair.AY)
} else {
assignViaExprEval(value.address)
}
}
is PtBinaryExpression -> {
val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
@ -3159,10 +2828,6 @@ $jumpIfFalseLabel lda #0
addressExpr is PtIdentifier -> {
asmgen.storeAIntoPointerVar(addressExpr)
}
addressExpr is PtRpn -> {
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.finalOperator().operator, true))
storeViaExprEval()
}
addressExpr is PtBinaryExpression -> {
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
storeViaExprEval()

View File

@ -14,9 +14,9 @@ class ExperiCodeGen: ICodeGeneratorBackend {
errors: IErrorReporter
): IAssemblyProgram? {
if(options.useRPN) {
program.transformBinExprToRPN()
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
if(options.useNewExprCode) {
// TODO("transform BinExprs?")
// errors.warn("EXPERIMENTAL NEW EXPRESSION CODEGEN IS USED. CODE SIZE+SPEED POSSIBLY SUFFERS.", Position.DUMMY)
}
// you could write a code generator directly on the PtProgram AST,

View File

@ -92,13 +92,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
value.add(origAssign.value)
} else {
require(origAssign.operator.endsWith('='))
if(codeGen.program.binaryExpressionsAreRPN) {
value = PtRpn(origAssign.value.type, origAssign.value.position)
val left = origAssign.target.children.single() as PtExpression
val right = origAssign.value
value.add(left)
value.add(right)
value.add(PtRpnOperator(origAssign.operator.dropLast(1), origAssign.target.type, left.type, right.type, origAssign.position))
if(codeGen.options.useNewExprCode) {
TODO("use something else than a BinExpr?")
} else {
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
val left: PtExpression = origAssign.target.children.single() as PtExpression
@ -272,13 +267,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
expressionEval.translateExpression(array.index)
} else {
val mult : PtExpression
if(codeGen.program.binaryExpressionsAreRPN) {
mult = PtRpn(DataType.UBYTE, array.position)
val left = array.index
val right = PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
mult.add(left)
mult.add(right)
mult.add(PtRpnOperator("*", DataType.UBYTE, left.type, right.type, array.position))
if(codeGen.options.useNewExprCode) {
TODO("use something else than a BinExpr?")
} else {
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
mult.children += array.index

View File

@ -93,7 +93,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
is PtPrefix -> translate(expr)
is PtArrayIndexer -> translate(expr)
is PtBinaryExpression -> translate(expr)
is PtRpn -> translate(expr)
is PtBuiltinFunctionCall -> codeGen.translateBuiltinFunc(expr)
is PtFunctionCall -> translate(expr)
is PtContainmentCheck -> translate(expr)
@ -316,10 +315,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
return ExpressionCodeResult(result, codeGen.irType(cast.type), actualResultReg2, actualResultFpReg2)
}
private fun translate(rpn: PtRpn): ExpressionCodeResult {
TODO("RPN expression (intermediate codegen) $rpn")
}
private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult {
val vmDt = codeGen.irType(binExpr.left.type)
val signed = binExpr.left.type in SignedDatatypes

View File

@ -269,8 +269,6 @@ class IRCodeGen(
is PtProgram,
is PtArrayIndexer,
is PtBinaryExpression,
is PtRpn,
is PtRpnOperator,
is PtIdentifier,
is PtWhenChoice,
is PtPrefix,
@ -912,39 +910,14 @@ class IRCodeGen(
else -> translateIfElseNonZeroComparison(ifElse, irDtLeft, signed)
}
}
is PtRpn -> {
val (left, oper, right) = condition.finalOperation()
if(oper.operator !in ComparisonOperators)
throw AssemblyError("if condition should only be a binary comparison expression")
val signed = oper.leftType in SignedDatatypes
val irDtLeft = irType(oper.leftType)
return when {
goto!=null && ifElse.elseScope.children.isEmpty() -> translateIfFollowedByJustGotoRPN(ifElse, goto, irDtLeft, signed)
constValue(right as PtExpression) == 0.0 -> translateIfElseZeroComparisonRPN(ifElse, irDtLeft, signed)
else -> translateIfElseNonZeroComparisonRPN(ifElse, irDtLeft, signed)
}
}
else -> {
throw AssemblyError("weird condition node: $condition")
}
}
}
private fun translateIfFollowedByJustGotoRPN(ifElse: PtIfElse, goto: PtJump, irDtLeft: IRDataType, signed: Boolean): MutableList<IRCodeChunkBase> {
TODO("RPN translateIfFollowedByJustGotoRPN")
}
private fun translateIfElseZeroComparisonRPN(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks {
TODO("RPN translateIfElseZeroComparisonRPN")
}
private fun translateIfElseNonZeroComparisonRPN(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks {
TODO("RPN translateIfElseNonZeroComparisonRPN")
}
private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump, irDtLeft: IRDataType, signed: Boolean): MutableList<IRCodeChunkBase> {
require(!program.binaryExpressionsAreRPN)
val condition = ifElse.condition as PtBinaryExpression
val result = mutableListOf<IRCodeChunkBase>()
if (irDtLeft == IRDataType.FLOAT) {
@ -1010,7 +983,6 @@ class IRCodeGen(
irDtLeft: IRDataType,
goto: PtJump
): MutableList<IRCodeChunkBase> {
require(!program.binaryExpressionsAreRPN)
val condition = ifElse.condition as PtBinaryExpression
val leftTr = expressionEval.translateExpression(condition.left)
addToResult(result, leftTr, leftTr.resultReg, -1)
@ -1039,7 +1011,6 @@ class IRCodeGen(
irDtLeft: IRDataType,
goto: PtJump
): MutableList<IRCodeChunkBase> {
require(!program.binaryExpressionsAreRPN)
val condition = ifElse.condition as PtBinaryExpression
val leftTr = expressionEval.translateExpression(condition.left)
addToResult(result, leftTr, leftTr.resultReg, -1)
@ -1093,7 +1064,6 @@ class IRCodeGen(
}
private fun translateIfElseZeroComparison(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks {
require(!program.binaryExpressionsAreRPN)
val result = mutableListOf<IRCodeChunkBase>()
val elseBranch: Opcode
val compResultReg: Int
@ -1155,7 +1125,6 @@ class IRCodeGen(
}
private fun translateIfElseNonZeroComparison(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks {
require(!program.binaryExpressionsAreRPN)
val result = mutableListOf<IRCodeChunkBase>()
val elseBranchOpcode: Opcode
val elseBranchFirstReg: Int

View File

@ -15,9 +15,9 @@ class VmCodeGen: ICodeGeneratorBackend {
errors: IErrorReporter
): IAssemblyProgram? {
if(options.useRPN) {
program.transformBinExprToRPN()
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
if(options.useNewExprCode) {
// TODO("transform BinExprs?")
// errors.warn("EXPERIMENTAL NEW EXPRESSION CODEGEN IS USED. CODE SIZE+SPEED POSSIBLY SUFFERS.", Position.DUMMY)
}

View File

@ -52,7 +52,7 @@ private fun compileMain(args: Array<String>): Boolean {
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM")
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)")
val varsHigh by cli.option(ArgType.Boolean, fullName = "varshigh", description = "put uninitialized variables in high memory area instead of at the end of the program")
val useRPN by cli.option(ArgType.Boolean, fullName = "rpn", description = "use RPN for expression code-generation (experimental)")
val useNewExprCode by cli.option(ArgType.Boolean, fullName = "newexpr", description = "use new expression code-gen (experimental)")
val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999)
try {
@ -127,7 +127,7 @@ private fun compileMain(args: Array<String>): Boolean {
asmListfile == true,
experimentalCodegen == true,
varsHigh == true,
useRPN == true,
useNewExprCode == true,
compilationTarget,
evalStackAddr,
processedSymbols,
@ -192,7 +192,7 @@ private fun compileMain(args: Array<String>): Boolean {
asmListfile == true,
experimentalCodegen == true,
varsHigh == true,
useRPN == true,
useNewExprCode == true,
compilationTarget,
evalStackAddr,
processedSymbols,

View File

@ -6,11 +6,9 @@ import prog8.ast.Program
import prog8.ast.base.AstException
import prog8.ast.expressions.Expression
import prog8.ast.expressions.NumericLiteral
import prog8.ast.printProgram
import prog8.ast.statements.Directive
import prog8.code.SymbolTableMaker
import prog8.code.ast.PtProgram
import prog8.code.ast.printAst
import prog8.code.core.*
import prog8.code.target.*
import prog8.codegen.vm.VmCodeGen
@ -38,7 +36,7 @@ class CompilerArguments(val filepath: Path,
val asmListfile: Boolean,
val experimentalCodegen: Boolean,
val varsHigh: Boolean,
val useRPN: Boolean,
val useNewExprCode: Boolean,
val compilationTarget: String,
val evalStackBaseAddress: UInt?,
val symbolDefs: Map<String, String>,
@ -79,7 +77,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
asmListfile = args.asmListfile
experimentalCodegen = args.experimentalCodegen
varsHigh = args.varsHigh
useRPN = args.useRPN
useNewExprCode = args.useNewExprCode
evalStackBaseAddress = args.evalStackBaseAddress
outputDir = args.outputDir.normalize()
symbolDefs = args.symbolDefs

View File

@ -452,8 +452,6 @@ class IntermediateAstMaker(private val program: Program, private val options: Co
}
private fun transform(srcExpr: BinaryExpression): PtBinaryExpression {
// NOTE: the Ast maker here will NOT create RPN-expression nodes for the code generator.
// If the code generator prefers RPN expressions, it has to transform the PtBinaryExpression itself into PtRpn.
val type = srcExpr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val actualType = if(type==DataType.BOOL) DataType.UBYTE else type
val expr = PtBinaryExpression(srcExpr.operator, actualType, srcExpr.position)

View File

@ -33,7 +33,7 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
asmListfile = false,
experimentalCodegen = false,
varsHigh = false,
useRPN = false,
useNewExprCode = false,
compilationTarget = target.name,
evalStackBaseAddress = null,
symbolDefs = emptyMap(),

View File

@ -50,7 +50,7 @@ class TestCompilerOptionSourcedirs: FunSpec({
asmListfile = false,
experimentalCodegen = false,
varsHigh = false,
useRPN = false,
useNewExprCode = false,
compilationTarget = Cx16Target.NAME,
evalStackBaseAddress = null,
symbolDefs = emptyMap(),

View File

@ -1,45 +0,0 @@
package prog8tests.codegeneration
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import prog8.code.ast.PtAssignment
import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.ast.PtRpn
import prog8.code.core.DataType
import prog8.code.target.C64Target
import prog8tests.helpers.compileText
class TestRPNCodeGen: FunSpec({
test("rpn 6502") {
val text="""
main {
sub start() {
uword pointer = 4000
uword a = 11
uword b = 22
uword c = 33
cx16.r0 = peekw(pointer+a+b*c+42)
pokew(pointer+a+b*c+42, 4242)
}
}"""
val result = compileText(C64Target(), false, text, writeAssembly = true, useRPN = true)!!
val ast = result.codegenAst!!
val statements = ast.entrypoint()!!.children
statements.size shouldBe 11
val peekw = (statements[8] as PtAssignment).value as PtBuiltinFunctionCall
val pokew = (statements[9] as PtBuiltinFunctionCall)
val rpn1 = peekw.args.first() as PtRpn
val rpn2 = pokew.args.first() as PtRpn
rpn1.children.size shouldBe 7
val depth1 = rpn1.maxDepth()
depth1.getValue(DataType.UBYTE) shouldBe 0
depth1.getValue(DataType.UWORD) shouldBe 3
depth1.getValue(DataType.FLOAT) shouldBe 0
rpn2.children.size shouldBe 7
val depth2 = rpn2.maxDepth()
depth2.getValue(DataType.UBYTE) shouldBe 0
depth2.getValue(DataType.UWORD) shouldBe 3
depth2.getValue(DataType.FLOAT) shouldBe 0
}
})

View File

@ -160,9 +160,9 @@ main {
qq = 16000 + c*${'$'}0008
}
}"""
compileText(C64Target(), true, text, writeAssembly = true, useRPN = false) shouldNotBe null
compileText(C64Target(), true, text, writeAssembly = true, useRPN = true) shouldNotBe null
compileText(VMTarget(), true, text, writeAssembly = true, useRPN = false) shouldNotBe null
// TODO RPN once IR RPN codegen is done: compileText(VMTarget(), true, text, writeAssembly = true, useRPN = true) shouldNotBe null
compileText(C64Target(), true, text, writeAssembly = true, useNewExprCode = false) shouldNotBe null
compileText(VMTarget(), true, text, writeAssembly = true, useNewExprCode = false) shouldNotBe null
compileText(C64Target(), true, text, writeAssembly = true, useNewExprCode = true) shouldNotBe null
compileText(VMTarget(), true, text, writeAssembly = true, useNewExprCode = true) shouldNotBe null
}
})

View File

@ -18,7 +18,7 @@ internal fun compileFile(
errors: IErrorReporter? = null,
writeAssembly: Boolean = true,
optFloatExpr: Boolean = true,
useRPN: Boolean = false
useNewExprCode: Boolean = false
) : CompilationResult? {
val filepath = fileDir.resolve(fileName)
assumeReadableFile(filepath)
@ -32,7 +32,7 @@ internal fun compileFile(
asmListfile = false,
experimentalCodegen = false,
varsHigh = false,
useRPN = useRPN,
useNewExprCode = useNewExprCode,
platform.name,
evalStackBaseAddress = null,
symbolDefs = emptyMap(),
@ -54,11 +54,11 @@ internal fun compileText(
errors: IErrorReporter? = null,
writeAssembly: Boolean = true,
optFloatExpr: Boolean = true,
useRPN: Boolean = false
useNewExprCode: Boolean = false
) : CompilationResult? {
val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8")
// we don't assumeNotExists(filePath) - should be ok to just overwrite it
filePath.toFile().writeText(sourceText)
return compileFile(platform, optimize, filePath.parent, filePath.name,
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, useRPN=useRPN)
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, useNewExprCode=useNewExprCode)
}

View File

@ -1,26 +1,14 @@
TODO
====
replace RPN by something that actually works and is efficient...
RPN: assembler fails selftest (something with output file name extension being wrong!)
RPN: swirl is MUCH slower
RPN: wizzine is slightly slower
RPN: bsieve is much slower
then:
RPN: swirl is bigger
RPN: petaxian is 900 bytes larger, chess is a lot bigger
RPN: cube3d is much larger, but a bit faster
RPN: cube3d-float is massive and slow
RPN: mandelbrot is bigger, but seems faster
RPN: Implement RPN codegen for IR.
For next minor release
^^^^^^^^^^^^^^^^^^^^^^
- ubyte fits = cx<numCellsHoriz-1 much larger code than when declared as bool. (RPN only?)
- if fits and @(celladdr(cx+1)) much larger code than if fits and not @(celladdr(cx+1)) (RPN only?)
- @($5000 + c<<$0003) = 22 why is 22 pushed on the stack first and then popped after the address is calcualted
- ubyte fits = cx<numCellsHoriz-1 much larger code than when declared as bool ????
- if fits and @(celladdr(cx+1)) much larger code than if fits and not @(celladdr(cx+1)) ????
- @($5000 + c<<$0003) = 22 why is 22 pushed on the stack first and then popped after the address is calculated
...

View File

@ -43,7 +43,7 @@ class RequestParser : Take {
asmListfile = false,
experimentalCodegen = false,
varsHigh = false,
useRPN = false
useNewExprCode = false
)
val compilationResult = compileProgram(args)
return RsJson(Jsonding())