mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
added first implementation of RPN 6502 codegen - all via stackeval still
This commit is contained in:
parent
9241479da4
commit
8c0a93779b
@ -265,7 +265,7 @@ class PtRpn(type: DataType, position: Position): PtExpression(type, position) {
|
||||
return Pair(maxDepths, numPushes)
|
||||
}
|
||||
|
||||
fun finalOperator(): String? = (children.last() as? PtRpnOperator)?.operator
|
||||
fun finalOperator() = children.last() as? PtRpnOperator
|
||||
fun finalFirstOperand() = children[children.size-3]
|
||||
fun finalSecondOperand() = children[children.size-2]
|
||||
}
|
||||
@ -273,9 +273,6 @@ class PtRpn(type: DataType, position: Position): PtExpression(type, position) {
|
||||
class PtRpnOperator(val operator: String, val type: DataType, val operand1Type: DataType, val operand2Type: 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.
|
||||
require(operand1Type equalsSize operand2Type) {
|
||||
"operand type size(s) differ: $operand1Type $operand2Type oper: $operator"
|
||||
}
|
||||
if(operator !in ComparisonOperators) {
|
||||
require(type equalsSize operand1Type && type equalsSize operand2Type) {
|
||||
"operand type size(s) differ from operator result type $type: $operand1Type $operand2Type oper: $operator"
|
||||
@ -342,6 +339,8 @@ class PtNumber(type: DataType, val number: Double, position: Position) : PtExpre
|
||||
}
|
||||
|
||||
operator fun compareTo(other: PtNumber): Int = number.compareTo(other.number)
|
||||
|
||||
override fun toString() = "PtNumber:$type:$number"
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,8 +100,8 @@ class PtForLoop(position: Position) : PtNode(position) {
|
||||
|
||||
|
||||
class PtIfElse(position: Position) : PtNode(position) {
|
||||
val condition: PtNode
|
||||
get() = children[0]
|
||||
val condition: PtExpression // either PtRpn or PtBinaryExpression
|
||||
get() = children[0] as PtExpression
|
||||
val ifScope: PtNodeGroup
|
||||
get() = children[1] as PtNodeGroup
|
||||
val elseScope: PtNodeGroup
|
||||
|
@ -21,8 +21,10 @@ class AsmGen6502: ICodeGeneratorBackend {
|
||||
options: CompilationOptions,
|
||||
errors: IErrorReporter
|
||||
): IAssemblyProgram? {
|
||||
if(options.useRPN)
|
||||
if(options.useRPN) {
|
||||
program.transformBinExprToRPN()
|
||||
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
|
||||
}
|
||||
|
||||
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
|
||||
return asmgen.compileToAssembly()
|
||||
@ -548,11 +550,32 @@ class AsmGen6502Internal (
|
||||
|
||||
private fun translate(stmt: PtIfElse) {
|
||||
if(stmt.condition is PtRpn) {
|
||||
TODO("RPN")
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
// both true and else parts
|
||||
val elseLabel = makeLabel("if_else")
|
||||
val endLabel = makeLabel("if_end")
|
||||
translateCompareAndJumpIfFalseRPN(condition, elseLabel)
|
||||
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) {
|
||||
@ -578,7 +601,7 @@ class AsmGen6502Internal (
|
||||
}
|
||||
|
||||
private fun requireComparisonExpression(condition: PtExpression) {
|
||||
if (!(condition is PtRpn && condition.finalOperator() in ComparisonOperators) && !(condition is PtBinaryExpression && condition.operator in ComparisonOperators))
|
||||
if (!(condition is PtRpn && condition.finalOperator()?.operator in ComparisonOperators) && !(condition is PtBinaryExpression && condition.operator in ComparisonOperators))
|
||||
throw AssemblyError("expected boolean comparison expression $condition")
|
||||
}
|
||||
|
||||
@ -984,7 +1007,7 @@ $repeatLabel lda $counterVar
|
||||
|
||||
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: PtExpression): Pair<PtExpression, PtExpression>? {
|
||||
if (pointerOffsetExpr is PtRpn) {
|
||||
TODO("RPN")
|
||||
TODO("RPN determine pointer+index via reg.") // however, is this ever getting called from RPN code?
|
||||
}
|
||||
else if (pointerOffsetExpr is PtBinaryExpression) {
|
||||
if (pointerOffsetExpr.operator != "+") return null
|
||||
@ -1103,6 +1126,22 @@ $repeatLabel lda $counterVar
|
||||
return node.definingSub()?.parameters?.singleOrNull { it.name===name }
|
||||
}
|
||||
|
||||
private fun translateCompareAndJumpIfTrueRPN(expr: PtRpn, jump: PtJump) {
|
||||
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")
|
||||
}
|
||||
assignExpressionToRegister(expr, RegisterOrPair.A)
|
||||
out(" bne $label")
|
||||
}
|
||||
|
||||
private fun translateCompareAndJumpIfFalseRPN(expr: PtRpn, jumpIfFalseLabel: String) {
|
||||
assignExpressionToRegister(expr, RegisterOrPair.A)
|
||||
out(" beq $jumpIfFalseLabel")
|
||||
}
|
||||
|
||||
private fun translateCompareAndJumpIfTrue(expr: PtBinaryExpression, jump: PtJump) {
|
||||
if(expr.operator !in ComparisonOperators)
|
||||
throw AssemblyError("must be comparison expression")
|
||||
@ -2850,7 +2889,8 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
}
|
||||
is PtRpn -> {
|
||||
TODO("translate RPN $expr")
|
||||
// TODO RPN: optimized memread address
|
||||
assignViaExprEval()
|
||||
}
|
||||
else -> assignViaExprEval()
|
||||
}
|
||||
|
@ -662,7 +662,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
is PtRpn -> {
|
||||
TODO("pokeW for RPN $addrExpr")
|
||||
// TODO RPN: optimized addr+index
|
||||
// for now: fall through
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier && addrExpr.right is PtNumber) {
|
||||
@ -724,7 +725,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
is PtRpn -> {
|
||||
TODO("peekW for RPN $addrExpr")
|
||||
// TODO RPN: optimized pointer+index
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||
asmgen.out(" jsr prog8_lib.func_peekw")
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier && addrExpr.right is PtNumber) {
|
||||
|
@ -34,7 +34,7 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
is PtIdentifier -> translateExpression(expression)
|
||||
is PtFunctionCall -> translateFunctionCallResultOntoStack(expression)
|
||||
is PtBuiltinFunctionCall -> asmgen.translateBuiltinFunctionCallExpression(expression, true, null)
|
||||
is PtContainmentCheck -> throw AssemblyError("containment check as complex expression value is not supported")
|
||||
is PtContainmentCheck -> translateContainmentCheck(expression)
|
||||
is PtArray, is PtString -> throw AssemblyError("string/array literal value assignment should have been replaced by a variable")
|
||||
is PtRange -> throw AssemblyError("range expression should have been changed into array values")
|
||||
is PtMachineRegister -> throw AssemblyError("machine register ast node should not occur in 6502 codegen it is for IR code")
|
||||
@ -42,6 +42,11 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateContainmentCheck(check: PtContainmentCheck) {
|
||||
asmgen.assignExpressionToRegister(check, RegisterOrPair.A)
|
||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||
}
|
||||
|
||||
private fun translateFunctionCallResultOntoStack(call: PtFunctionCall) {
|
||||
// only for use in nested expression evaluation
|
||||
|
||||
@ -241,7 +246,46 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: PtRpn) {
|
||||
TODO("translate RPN $expr")
|
||||
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
|
||||
val oper = expr.finalOperator()!!
|
||||
val leftDt = oper.operand1Type
|
||||
val rightDt = oper.operand2Type
|
||||
|
||||
// comparison against zero
|
||||
if(oper.operator in ComparisonOperators) {
|
||||
if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) {
|
||||
val rightVal = (expr.finalSecondOperand() as PtExpression).asConstInteger()
|
||||
if(rightVal==0)
|
||||
return translateComparisonWithZero(expr.finalFirstOperand() as PtExpression, leftDt, oper.operator)
|
||||
}
|
||||
}
|
||||
|
||||
// string compare
|
||||
if(leftDt==DataType.STR && rightDt==DataType.STR && oper.operator in ComparisonOperators) {
|
||||
return translateCompareStrings(expr.finalFirstOperand() as PtExpression, oper.operator, expr.finalSecondOperand() 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.finalSecondOperand()}")
|
||||
|
||||
var depth=0
|
||||
expr.children.forEach {
|
||||
if(it is PtRpnOperator) {
|
||||
when(it.operand1Type) {
|
||||
in ByteDatatypes -> translateBinaryOperatorBytes(it.operator, it.operand1Type)
|
||||
in WordDatatypes -> translateBinaryOperatorWords(it.operator, it.operand1Type)
|
||||
DataType.FLOAT -> translateBinaryOperatorFloats(it.operator)
|
||||
else -> throw AssemblyError("non-numerical datatype ${it.operand1Type}")
|
||||
}
|
||||
depth--
|
||||
} else {
|
||||
translateExpressionInternal(it as PtExpression)
|
||||
depth++
|
||||
}
|
||||
}
|
||||
require(depth==1) { "unbalanced RPN: $depth ${expr.position}" }
|
||||
}
|
||||
|
||||
private fun translateExpression(expr: PtBinaryExpression) {
|
||||
|
@ -142,7 +142,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
assignMemoryByte(assign.target, null, value.address as PtIdentifier)
|
||||
}
|
||||
is PtRpn -> {
|
||||
TODO("translate RPN ${value.address}")
|
||||
// TODO RPN: optimized pointer access
|
||||
assignViaExprEval(value.address)
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(value.address as PtBinaryExpression, false)) {
|
||||
@ -305,8 +306,9 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
fallbackToStackEval(assign)
|
||||
}
|
||||
}
|
||||
is PtRpn ->{
|
||||
TODO("assign RPN expression $value depth=${value.maxDepth()}")
|
||||
is PtRpn -> {
|
||||
// TODO RPN: optimized evaluation
|
||||
fallbackToStackEval(assign)
|
||||
}
|
||||
else -> throw AssemblyError("weird assignment value type $value")
|
||||
}
|
||||
@ -907,7 +909,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
assignMemoryByteIntoWord(target, null, value.address as PtIdentifier)
|
||||
}
|
||||
is PtRpn -> {
|
||||
TODO("translate RPN ${value.address}")
|
||||
// TODO RPN: optimized pointer access
|
||||
assignViaExprEval(value.address)
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(value.address as PtBinaryExpression, false)) {
|
||||
@ -2831,7 +2834,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.storeAIntoPointerVar(addressExpr)
|
||||
}
|
||||
addressExpr is PtRpn -> {
|
||||
TODO("translate RPN $addressExpr")
|
||||
// TODO RPN: optimize pointer access
|
||||
storeViaExprEval()
|
||||
}
|
||||
addressExpr is PtBinaryExpression -> {
|
||||
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, true))
|
||||
|
@ -2,10 +2,7 @@ package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
import prog8.code.core.ICodeGeneratorBackend
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.code.core.*
|
||||
import prog8.codegen.intermediate.IRCodeGen
|
||||
import prog8.intermediate.IRFileWriter
|
||||
|
||||
@ -17,8 +14,10 @@ class ExperiCodeGen: ICodeGeneratorBackend {
|
||||
errors: IErrorReporter
|
||||
): IAssemblyProgram? {
|
||||
|
||||
if(options.useRPN)
|
||||
if(options.useRPN) {
|
||||
program.transformBinExprToRPN()
|
||||
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
|
||||
}
|
||||
|
||||
// you could write a code generator directly on the PtProgram AST,
|
||||
// but you can also use the Intermediate Representation to build a codegen on:
|
||||
|
@ -93,7 +93,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
} else {
|
||||
require(origAssign.operator.endsWith('='))
|
||||
if(codeGen.program.binaryExpressionsAreRPN) {
|
||||
TODO("RPN")
|
||||
TODO("RPN fallbackassign alt.")
|
||||
} else {
|
||||
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
|
||||
val left: PtExpression = origAssign.target.children.single() as PtExpression
|
||||
@ -267,7 +267,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
expressionEval.translateExpression(array.index)
|
||||
} else {
|
||||
if(codeGen.program.binaryExpressionsAreRPN) {
|
||||
TODO("RPN")
|
||||
TODO("RPN loadindexreg alt.")
|
||||
} else {
|
||||
val mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
mult.children += array.index
|
||||
|
@ -317,7 +317,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
|
||||
private fun translate(rpn: PtRpn): ExpressionCodeResult {
|
||||
TODO("translate RPN expression $rpn")
|
||||
TODO("RPN expression $rpn")
|
||||
}
|
||||
|
||||
private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult {
|
||||
|
@ -913,7 +913,7 @@ class IRCodeGen(
|
||||
}
|
||||
}
|
||||
is PtRpn -> {
|
||||
TODO("RPN")
|
||||
TODO("RPN ifelse $condition")
|
||||
}
|
||||
else -> {
|
||||
TODO("weird condition node: $condition")
|
||||
|
@ -2,10 +2,7 @@ package prog8.codegen.vm
|
||||
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
import prog8.code.core.ICodeGeneratorBackend
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.code.core.*
|
||||
import prog8.codegen.intermediate.IRCodeGen
|
||||
import prog8.intermediate.IRFileWriter
|
||||
import prog8.intermediate.IRProgram
|
||||
@ -18,8 +15,11 @@ class VmCodeGen: ICodeGeneratorBackend {
|
||||
errors: IErrorReporter
|
||||
): IAssemblyProgram? {
|
||||
|
||||
if(options.useRPN)
|
||||
if(options.useRPN) {
|
||||
program.transformBinExprToRPN()
|
||||
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
|
||||
}
|
||||
|
||||
|
||||
val irCodeGen = IRCodeGen(program, symbolTable, options, errors)
|
||||
val irProgram = irCodeGen.generate()
|
||||
|
Loading…
x
Reference in New Issue
Block a user