mirror of
https://github.com/irmen/prog8.git
synced 2025-04-09 00:37:15 +00:00
Merge branch 'rpn-expressions'
This commit is contained in:
commit
c50c9ca545
@ -15,7 +15,12 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
|
||||
* This gives the fastest lookup possible (no need to traverse tree nodes)
|
||||
*/
|
||||
|
||||
val flat: Map<String, StNode> by lazy {
|
||||
private var cachedFlat: Map<String, StNode>? = null
|
||||
|
||||
val flat: Map<String, StNode> get() {
|
||||
if(cachedFlat!=null)
|
||||
return cachedFlat!!
|
||||
|
||||
val result = mutableMapOf<String, StNode>()
|
||||
fun collect(node: StNode) {
|
||||
for(child in node.children) {
|
||||
@ -24,7 +29,12 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
|
||||
}
|
||||
}
|
||||
collect(this)
|
||||
result
|
||||
cachedFlat = result
|
||||
return result
|
||||
}
|
||||
|
||||
fun resetCachedFlat() {
|
||||
cachedFlat = null
|
||||
}
|
||||
|
||||
val allVariables: Collection<StStaticVariable> by lazy {
|
||||
|
@ -53,7 +53,8 @@ sealed class PtNamedNode(var name: String, position: Position): PtNode(position)
|
||||
class PtProgram(
|
||||
val name: String,
|
||||
val memsizer: IMemSizer,
|
||||
val encoding: IStringEncoding
|
||||
val encoding: IStringEncoding,
|
||||
var binaryExpressionsAreRPN: Boolean = false
|
||||
) : PtNode(Position.DUMMY) {
|
||||
|
||||
// fun allModuleDirectives(): Sequence<PtDirective> =
|
||||
@ -64,6 +65,45 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@ package prog8.code.ast
|
||||
import prog8.code.core.*
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.round
|
||||
|
||||
|
||||
@ -27,6 +28,7 @@ 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
|
||||
@ -62,6 +64,7 @@ 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
|
||||
@ -158,6 +161,129 @@ 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())
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
@ -215,6 +341,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"
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@ import prog8.code.core.*
|
||||
* Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root),
|
||||
* passing it as a String to the specified receiver function.
|
||||
*/
|
||||
fun printAst(root: PtNode, output: (text: String) -> Unit) {
|
||||
fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Unit) {
|
||||
fun type(dt: DataType) = "!${dt.name.lowercase()}!"
|
||||
fun txt(node: PtNode): String {
|
||||
return when(node) {
|
||||
@ -19,6 +19,8 @@ fun printAst(root: PtNode, output: (text: String) -> Unit) {
|
||||
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 PtBuiltinFunctionCall -> {
|
||||
val str = if(node.void) "void " else ""
|
||||
str + node.name + "()"
|
||||
@ -134,16 +136,22 @@ fun printAst(root: PtNode, output: (text: String) -> Unit) {
|
||||
root.children.forEach {
|
||||
walkAst(it) { node, depth ->
|
||||
val txt = txt(node)
|
||||
if(txt.isNotEmpty())
|
||||
output(" ".repeat(depth) + txt(node))
|
||||
val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
|
||||
if(!library || !skipLibraries) {
|
||||
if (txt.isNotEmpty())
|
||||
output(" ".repeat(depth) + txt(node))
|
||||
}
|
||||
}
|
||||
}
|
||||
println()
|
||||
} else {
|
||||
walkAst(root) { node, depth ->
|
||||
val txt = txt(node)
|
||||
if(txt.isNotEmpty())
|
||||
output(" ".repeat(depth) + txt(node))
|
||||
val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
|
||||
if(!library || !skipLibraries) {
|
||||
if (txt.isNotEmpty())
|
||||
output(" ".repeat(depth) + txt(node))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,8 +100,8 @@ class PtForLoop(position: Position) : PtNode(position) {
|
||||
|
||||
|
||||
class PtIfElse(position: Position) : PtNode(position) {
|
||||
val condition: PtBinaryExpression
|
||||
get() = children[0] as PtBinaryExpression
|
||||
val condition: PtExpression // either PtRpn or PtBinaryExpression
|
||||
get() = children[0] as PtExpression
|
||||
val ifScope: PtNodeGroup
|
||||
get() = children[1] as PtNodeGroup
|
||||
val elseScope: PtNodeGroup
|
||||
|
@ -20,6 +20,7 @@ class CompilationOptions(val output: OutputType,
|
||||
var asmListfile: Boolean = false,
|
||||
var experimentalCodegen: Boolean = false,
|
||||
var varsHigh: Boolean = false,
|
||||
var useRPN: Boolean = false,
|
||||
var evalStackBaseAddress: UInt? = null,
|
||||
var outputDir: Path = Path(""),
|
||||
var symbolDefs: Map<String, String> = emptyMap()
|
||||
|
@ -21,6 +21,13 @@ 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)
|
||||
}
|
||||
|
||||
// printAst(program, true) { println(it) }
|
||||
|
||||
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
|
||||
return asmgen.compileToAssembly()
|
||||
}
|
||||
@ -43,9 +50,9 @@ class AsmGen6502Internal (
|
||||
private val forloopsAsmGen = ForLoopsAsmGen(program, this, zeropage)
|
||||
private val postincrdecrAsmGen = PostIncrDecrAsmGen(program, this)
|
||||
private val functioncallAsmGen = FunctionCallAsmGen(program, this)
|
||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator)
|
||||
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
|
||||
private val assignmentAsmGen = AssignmentAsmGen(program, this, allocator)
|
||||
private val assignmentAsmGen = AssignmentAsmGen(program, symbolTable, this, allocator)
|
||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator)
|
||||
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
|
||||
|
||||
fun compileToAssembly(): IAssemblyProgram? {
|
||||
@ -467,17 +474,17 @@ class AsmGen6502Internal (
|
||||
internal fun restoreXafterCall(functionCall: PtFunctionCall) =
|
||||
functioncallAsmGen.restoreXafterCall(functionCall)
|
||||
|
||||
internal fun translateNormalAssignment(assign: AsmAssignment) =
|
||||
assignmentAsmGen.translateNormalAssignment(assign)
|
||||
internal fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) =
|
||||
assignmentAsmGen.translateNormalAssignment(assign, scope)
|
||||
|
||||
internal fun assignExpressionToRegister(expr: PtExpression, register: RegisterOrPair, signed: Boolean=false) =
|
||||
assignmentAsmGen.assignExpressionToRegister(expr, register, signed)
|
||||
|
||||
internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType, scope: IPtSubroutine?) =
|
||||
assignmentAsmGen.assignExpressionToVariable(expr, asmVarName, dt, scope)
|
||||
internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType) =
|
||||
assignmentAsmGen.assignExpressionToVariable(expr, asmVarName, dt)
|
||||
|
||||
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, pos: Position, signed: Boolean=false) =
|
||||
assignmentAsmGen.assignVariableToRegister(asmVarName, register, signed, pos)
|
||||
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, scope: IPtSubroutine?, pos: Position, signed: Boolean=false) =
|
||||
assignmentAsmGen.assignVariableToRegister(asmVarName, register, signed, scope, pos)
|
||||
|
||||
internal fun assignRegister(reg: RegisterOrPair, target: AsmAssignTarget) {
|
||||
when(reg) {
|
||||
@ -507,7 +514,7 @@ class AsmGen6502Internal (
|
||||
AsmAssignment(
|
||||
AsmAssignSource(SourceStorageKind.REGISTER, program, this, target.datatype, register=RegisterOrPair.AY),
|
||||
target, program.memsizer, value.position
|
||||
)
|
||||
), value.definingISub()
|
||||
)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
@ -544,35 +551,59 @@ class AsmGen6502Internal (
|
||||
}
|
||||
|
||||
private fun translate(stmt: PtIfElse) {
|
||||
requireComparisonExpression(stmt.condition) // IfStatement: condition must be of form 'x <comparison> <value>'
|
||||
val booleanCondition = stmt.condition
|
||||
|
||||
if (stmt.elseScope.children.isEmpty()) {
|
||||
val jump = stmt.ifScope.children.singleOrNull()
|
||||
if(jump is PtJump) {
|
||||
translateCompareAndJumpIfTrue(booleanCondition, jump)
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
// both true and else parts
|
||||
val elseLabel = makeLabel("if_else")
|
||||
val endLabel = makeLabel("if_end")
|
||||
translateCompareAndJumpIfFalse(booleanCondition, endLabel)
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
else {
|
||||
// both true and else parts
|
||||
val elseLabel = makeLabel("if_else")
|
||||
val endLabel = makeLabel("if_end")
|
||||
translateCompareAndJumpIfFalse(booleanCondition, elseLabel)
|
||||
translate(stmt.ifScope)
|
||||
jmp(endLabel)
|
||||
out(elseLabel)
|
||||
translate(stmt.elseScope)
|
||||
out(endLabel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun requireComparisonExpression(condition: PtExpression) {
|
||||
if(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")
|
||||
}
|
||||
|
||||
@ -597,11 +628,11 @@ class AsmGen6502Internal (
|
||||
val name = asmVariableName(stmt.count as PtIdentifier)
|
||||
when(vardecl.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
assignVariableToRegister(name, RegisterOrPair.Y, stmt.count.position)
|
||||
assignVariableToRegister(name, RegisterOrPair.Y, stmt.definingISub(), stmt.count.position)
|
||||
repeatCountInY(stmt, endLabel)
|
||||
}
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
assignVariableToRegister(name, RegisterOrPair.AY, stmt.count.position)
|
||||
assignVariableToRegister(name, RegisterOrPair.AY, stmt.definingISub(), stmt.count.position)
|
||||
repeatWordCountInAY(endLabel, stmt)
|
||||
}
|
||||
else -> throw AssemblyError("invalid loop variable datatype $vardecl")
|
||||
@ -977,33 +1008,78 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
|
||||
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: PtExpression): Pair<PtExpression, PtExpression>? {
|
||||
if(pointerOffsetExpr is PtBinaryExpression && pointerOffsetExpr.operator=="+") {
|
||||
val leftDt = pointerOffsetExpr.left.type
|
||||
val rightDt = pointerOffsetExpr.right.type
|
||||
if(leftDt == DataType.UWORD && rightDt == DataType.UBYTE)
|
||||
return Pair(pointerOffsetExpr.left, pointerOffsetExpr.right)
|
||||
if(leftDt == DataType.UBYTE && rightDt == DataType.UWORD)
|
||||
return Pair(pointerOffsetExpr.right, pointerOffsetExpr.left)
|
||||
if(leftDt == DataType.UWORD && rightDt == DataType.UWORD) {
|
||||
// could be that the index was a constant numeric byte but converted to word, check that
|
||||
val constIdx = pointerOffsetExpr.right as? PtNumber
|
||||
if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) {
|
||||
return Pair(pointerOffsetExpr.left, PtNumber(DataType.UBYTE, constIdx.number, constIdx.position))
|
||||
}
|
||||
// could be that the index was typecasted into uword, check that
|
||||
val rightTc = pointerOffsetExpr.right as? PtTypeCast
|
||||
if(rightTc!=null && rightTc.value.type == DataType.UBYTE)
|
||||
return Pair(pointerOffsetExpr.left, rightTc.value)
|
||||
val leftTc = pointerOffsetExpr.left as? PtTypeCast
|
||||
if(leftTc!=null && leftTc.value.type == DataType.UBYTE)
|
||||
return Pair(pointerOffsetExpr.right, leftTc.value)
|
||||
}
|
||||
val left: PtExpression
|
||||
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
|
||||
pointerOffsetExpr.children.removeLast()
|
||||
pointerOffsetExpr.children.removeLast()
|
||||
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))
|
||||
smallExpr.addRpnNode(rightmostOperand)
|
||||
smallExpr.addRpnNode(rightmostOperator)
|
||||
smallExpr.parent = pointerOffsetExpr.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 (operator != "+") return null
|
||||
val leftDt = left.type
|
||||
val rightDt = right.type
|
||||
if(leftDt == DataType.UWORD && rightDt == DataType.UBYTE)
|
||||
return Pair(left, right)
|
||||
if(leftDt == DataType.UBYTE && rightDt == DataType.UWORD)
|
||||
return Pair(right, left)
|
||||
if(leftDt == DataType.UWORD && rightDt == DataType.UWORD) {
|
||||
// could be that the index was a constant numeric byte but converted to word, check that
|
||||
val constIdx = right as? PtNumber
|
||||
if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) {
|
||||
val num = PtNumber(DataType.UBYTE, constIdx.number, constIdx.position)
|
||||
num.parent = right.parent
|
||||
return Pair(left, num)
|
||||
}
|
||||
// could be that the index was typecasted into uword, check that
|
||||
val rightTc = right as? PtTypeCast
|
||||
if(rightTc!=null && rightTc.value.type == DataType.UBYTE)
|
||||
return Pair(left, rightTc.value)
|
||||
val leftTc = left as? PtTypeCast
|
||||
if(leftTc!=null && leftTc.value.type == DataType.UBYTE)
|
||||
return Pair(right, leftTc.value)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
internal fun tryOptimizedPointerAccessWithA(expr: PtBinaryExpression, write: Boolean): Boolean {
|
||||
internal fun tryOptimizedPointerAccessWithA(addressExpr: PtExpression, operator: String, write: Boolean): Boolean {
|
||||
// optimize pointer,indexregister if possible
|
||||
|
||||
fun evalBytevalueWillClobberA(expr: PtExpression): Boolean {
|
||||
@ -1019,9 +1095,8 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(expr.operator=="+") {
|
||||
val ptrAndIndex = pointerViaIndexRegisterPossible(expr)
|
||||
if(operator=="+") {
|
||||
val ptrAndIndex = pointerViaIndexRegisterPossible(addressExpr)
|
||||
if(ptrAndIndex!=null) {
|
||||
val pointervar = ptrAndIndex.first as? PtIdentifier
|
||||
val target = if(pointervar==null) null else symbolTable.lookup(pointervar.name)!!.astNode
|
||||
@ -1047,14 +1122,14 @@ $repeatLabel lda $counterVar
|
||||
if(saveA)
|
||||
out(" pha")
|
||||
if(ptrAndIndex.second.isSimple()) {
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
|
||||
if(saveA)
|
||||
out(" pla")
|
||||
out(" sta (P8ZP_SCRATCH_W2),y")
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, ptrAndIndex.second)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
restoreRegisterStack(CpuRegister.Y, true)
|
||||
if(saveA)
|
||||
out(" pla")
|
||||
@ -1068,12 +1143,12 @@ $repeatLabel lda $counterVar
|
||||
} else {
|
||||
// copy the pointer var to zp first
|
||||
if(ptrAndIndex.second.isSimple()) {
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
|
||||
out(" lda (P8ZP_SCRATCH_W2),y")
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, ptrAndIndex.second)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
out(" lda (P8ZP_SCRATCH_W2),y")
|
||||
}
|
||||
@ -1089,12 +1164,67 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
|
||||
internal fun findSubroutineParameter(name: String, asmgen: AsmGen6502Internal): PtSubroutineParameter? {
|
||||
val node = asmgen.symbolTable.lookup(name)!!.astNode
|
||||
val stScope = asmgen.symbolTable.lookup(name)
|
||||
require(stScope!=null) {
|
||||
"invalid name lookup $name"
|
||||
}
|
||||
val node = stScope.astNode
|
||||
if(node is PtSubroutineParameter)
|
||||
return node
|
||||
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.children.removeLast()
|
||||
expr.children.removeLast()
|
||||
expr
|
||||
} 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.children.removeLast()
|
||||
expr.children.removeLast()
|
||||
expr
|
||||
} 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")
|
||||
@ -1287,7 +1417,7 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
}
|
||||
|
||||
private fun testNonzeroComparisonAndJump(
|
||||
internal fun testNonzeroComparisonAndJump(
|
||||
left: PtExpression,
|
||||
operator: String,
|
||||
right: PtExpression,
|
||||
@ -1398,7 +1528,7 @@ $repeatLabel lda $counterVar
|
||||
} else {
|
||||
val subroutine = left.definingSub()!!
|
||||
subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
out("""
|
||||
lda #<$subroutineFloatEvalResultVar1
|
||||
@ -1443,7 +1573,7 @@ $repeatLabel lda $counterVar
|
||||
} else {
|
||||
val subroutine = left.definingSub()!!
|
||||
subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
out("""
|
||||
lda #<$subroutineFloatEvalResultVar1
|
||||
@ -1488,7 +1618,7 @@ $repeatLabel lda $counterVar
|
||||
} else {
|
||||
val subroutine = left.definingSub()!!
|
||||
subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
out("""
|
||||
lda #<$subroutineFloatEvalResultVar1
|
||||
@ -1533,7 +1663,7 @@ $repeatLabel lda $counterVar
|
||||
} else {
|
||||
val subroutine = left.definingSub()!!
|
||||
subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
out("""
|
||||
lda #<$subroutineFloatEvalResultVar1
|
||||
@ -1578,11 +1708,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
out(" pla")
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -1619,11 +1749,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
out(" pla")
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -1662,11 +1792,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.UWORD, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -1708,11 +1838,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.WORD, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -1755,11 +1885,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
out(" pla")
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -1798,11 +1928,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.BYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE)
|
||||
out(" pla")
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -1847,11 +1977,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.UWORD, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -1898,11 +2028,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(right.isSimple()) {
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD)
|
||||
assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.WORD, right)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -1946,11 +2076,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
out(" pla")
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -1989,11 +2119,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.BYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE)
|
||||
out(" pla")
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -2040,11 +2170,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.UWORD, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -2095,11 +2225,11 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
|
||||
if(right.isSimple()) {
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD)
|
||||
assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.WORD, right)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -2139,11 +2269,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
out(" pla")
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -2179,11 +2309,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.BYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE)
|
||||
out(" pla")
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -2221,11 +2351,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(right.isSimple()) {
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.UWORD, right)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -2267,11 +2397,11 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.WORD, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -2310,14 +2440,14 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else if(right.isSimple()) {
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(right, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
out(" cmp P8ZP_SCRATCH_B1 | bne $jumpIfFalseLabel")
|
||||
@ -2356,14 +2486,14 @@ $repeatLabel lda $counterVar
|
||||
return
|
||||
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else if(right.isSimple()) {
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
assignExpressionToRegister(right, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
return code("P8ZP_SCRATCH_B1")
|
||||
@ -2432,14 +2562,14 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
else -> {
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||
} else if(right.isSimple()) {
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.UWORD, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -2518,14 +2648,14 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
else -> {
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||
} else if (right.isSimple()) {
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.UWORD, left)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@ -2615,7 +2745,7 @@ $repeatLabel lda $counterVar
|
||||
} else {
|
||||
val subroutine = left.definingSub()!!
|
||||
subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
out("""
|
||||
lda #<$subroutineFloatEvalResultVar1
|
||||
@ -2700,7 +2830,7 @@ $repeatLabel lda $counterVar
|
||||
} else {
|
||||
val subroutine = left.definingSub()!!
|
||||
subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
out("""
|
||||
lda #<$subroutineFloatEvalResultVar1
|
||||
@ -2804,7 +2934,7 @@ $repeatLabel lda $counterVar
|
||||
internal fun translateDirectMemReadExpressionToRegAorStack(expr: PtMemoryByte, pushResultOnEstack: Boolean) {
|
||||
|
||||
fun assignViaExprEval() {
|
||||
assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
if (isTargetCpu(CpuType.CPU65c02)) {
|
||||
if (pushResultOnEstack) {
|
||||
out(" lda (P8ZP_SCRATCH_W2) | dex | sta P8ESTACK_LO+1,x")
|
||||
@ -2834,7 +2964,17 @@ $repeatLabel lda $counterVar
|
||||
out(" sta P8ESTACK_LO,x | dex")
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
if(tryOptimizedPointerAccessWithA(expr.address as PtBinaryExpression, false)) {
|
||||
val addrExpr = expr.address as PtBinaryExpression
|
||||
if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
|
||||
if(pushResultOnEstack)
|
||||
out(" sta P8ESTACK_LO,x | dex")
|
||||
} else {
|
||||
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 {
|
||||
|
@ -163,24 +163,24 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" cmp ${arg2.address.asConstInteger()!!.toHex()}")
|
||||
} else {
|
||||
if(arg1.isSimple()) {
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingISub())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
|
||||
asmgen.out(" cmp P8ZP_SCRATCH_B1")
|
||||
} else {
|
||||
asmgen.pushCpuStack(DataType.UBYTE, arg1)
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingISub())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.out(" pla | cmp P8ZP_SCRATCH_B1")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
if(arg1.isSimple()) {
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingISub())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
|
||||
asmgen.out(" cmp P8ZP_SCRATCH_B1")
|
||||
} else {
|
||||
asmgen.pushCpuStack(DataType.UBYTE, arg1)
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingISub())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.out(" pla | cmp P8ZP_SCRATCH_B1")
|
||||
}
|
||||
}
|
||||
@ -209,7 +209,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
else -> {
|
||||
if(arg1.isSimple()) {
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, fcall.definingISub())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD)
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
|
||||
asmgen.out("""
|
||||
cpy P8ZP_SCRATCH_W1+1
|
||||
@ -218,7 +218,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
+""")
|
||||
} else {
|
||||
asmgen.pushCpuStack(DataType.UWORD, arg1)
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, fcall.definingISub())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||
asmgen.out("""
|
||||
@ -250,7 +250,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
else
|
||||
AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen)
|
||||
val assign = AsmAssignment(src, target, program.memsizer, fcall.position)
|
||||
asmgen.translateNormalAssignment(assign)
|
||||
asmgen.translateNormalAssignment(assign, fcall.definingISub())
|
||||
}
|
||||
|
||||
private fun funcSqrt16(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||
@ -550,14 +550,14 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
if(arrayvar.type==DataType.UWORD) {
|
||||
if(dt!='b')
|
||||
throw AssemblyError("non-array var indexing requires bytes dt")
|
||||
asmgen.assignExpressionToVariable(arrayvar, "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD, null)
|
||||
asmgen.assignExpressionToVariable(arrayvar, "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD)
|
||||
} else {
|
||||
val addressOf = PtAddressOf(arrayvar.position)
|
||||
addressOf.add(arrayvar)
|
||||
addressOf.parent = arrayvar.parent.parent
|
||||
asmgen.assignExpressionToVariable(addressOf, "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD, null)
|
||||
asmgen.assignExpressionToVariable(addressOf, "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD)
|
||||
}
|
||||
asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE, null)
|
||||
asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE)
|
||||
}
|
||||
|
||||
private fun funcSgn(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||
@ -661,35 +661,41 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
return
|
||||
}
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier && addrExpr.right is PtNumber) {
|
||||
val varname = asmgen.asmVariableName(addrExpr.left as PtIdentifier)
|
||||
if(asmgen.isZpVar(addrExpr.left as PtIdentifier)) {
|
||||
// pointervar is already in the zero page, no need to copy
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!)
|
||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX)
|
||||
val index = (addrExpr.right as PtNumber).number.toHex()
|
||||
asmgen.out("""
|
||||
ldy #$index
|
||||
is PtRpn, is PtBinaryExpression -> {
|
||||
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
|
||||
val pointer = result?.first as? PtIdentifier
|
||||
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
|
||||
// can do ZP,Y indexing
|
||||
val varname = asmgen.asmVariableName(pointer)
|
||||
val scope = fcall.definingISub()!!
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
||||
asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y)
|
||||
asmgen.saveRegisterLocal(CpuRegister.Y, scope)
|
||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.Y)
|
||||
asmgen.out("""
|
||||
sta ($varname),y
|
||||
txa
|
||||
iny
|
||||
sta ($varname),y""")
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
return
|
||||
}
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
return
|
||||
}
|
||||
}
|
||||
else -> { /* fall through */ }
|
||||
}
|
||||
|
||||
// fall through method:
|
||||
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", DataType.UWORD, null)
|
||||
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", DataType.UWORD)
|
||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AY)
|
||||
asmgen.out(" jsr prog8_lib.func_pokew")
|
||||
}
|
||||
|
||||
private fun funcPeekW(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||
fun fallback() {
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||
asmgen.out(" jsr prog8_lib.func_peekw")
|
||||
}
|
||||
when(val addrExpr = fcall.args[0]) {
|
||||
is PtNumber -> {
|
||||
val addr = addrExpr.number.toHex()
|
||||
@ -715,38 +721,25 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
tay
|
||||
pla""")
|
||||
}
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||
asmgen.out(" jsr prog8_lib.func_peekw")
|
||||
}
|
||||
} else fallback()
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier && addrExpr.right is PtNumber) {
|
||||
val varname = asmgen.asmVariableName(addrExpr.left as PtIdentifier)
|
||||
if(asmgen.isZpVar(addrExpr.left as PtIdentifier)) {
|
||||
// pointervar is already in the zero page, no need to copy
|
||||
val index = (addrExpr.right as PtNumber).number.toHex()
|
||||
asmgen.out("""
|
||||
ldy #$index
|
||||
lda ($varname),y
|
||||
pha
|
||||
iny
|
||||
lda ($varname),y
|
||||
tay
|
||||
pla""")
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||
asmgen.out(" jsr prog8_lib.func_peekw")
|
||||
}
|
||||
} else {
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||
asmgen.out(" jsr prog8_lib.func_peekw")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||
asmgen.out(" jsr prog8_lib.func_peekw")
|
||||
is PtRpn, is PtBinaryExpression -> {
|
||||
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
|
||||
val pointer = result?.first as? PtIdentifier
|
||||
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
|
||||
// can do ZP,Y indexing
|
||||
val varname = asmgen.asmVariableName(pointer)
|
||||
asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y)
|
||||
asmgen.out("""
|
||||
lda ($varname),y
|
||||
pha
|
||||
iny
|
||||
lda ($varname),y
|
||||
tay
|
||||
pla""")
|
||||
} else fallback()
|
||||
}
|
||||
else -> fallback()
|
||||
}
|
||||
|
||||
if(resultToStack){
|
||||
@ -977,7 +970,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
val addr = PtAddressOf(value.position)
|
||||
addr.add(variable)
|
||||
addr.parent = call
|
||||
asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.FLOAT, scope)
|
||||
asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.FLOAT)
|
||||
AsmAssignSource.fromAstSource(addr, program, asmgen)
|
||||
}
|
||||
}
|
||||
@ -1005,7 +998,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, conv.dt, null, value.position, variableAsmName = varname)
|
||||
val assign = AsmAssignment(src, tgt, program.memsizer, value.position)
|
||||
asmgen.translateNormalAssignment(assign)
|
||||
asmgen.translateNormalAssignment(assign, scope)
|
||||
}
|
||||
conv.reg != null -> {
|
||||
val src = when (conv.dt) {
|
||||
@ -1023,7 +1016,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
val tgt = AsmAssignTarget.fromRegisters(conv.reg!!, false, value.position, null, asmgen)
|
||||
val assign = AsmAssignment(src, tgt, program.memsizer, value.position)
|
||||
asmgen.translateNormalAssignment(assign)
|
||||
asmgen.translateNormalAssignment(assign, scope)
|
||||
}
|
||||
else -> throw AssemblyError("callconv")
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ 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)
|
||||
@ -33,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")
|
||||
@ -41,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
|
||||
|
||||
@ -239,18 +245,114 @@ 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 -> {
|
||||
expr.children.removeLast()
|
||||
expr.children.removeLast()
|
||||
translateComparisonWithZero(expr, 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()}")
|
||||
|
||||
var depth=0
|
||||
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}")
|
||||
}
|
||||
depth--
|
||||
} else {
|
||||
translateExpressionInternal(it as PtExpression)
|
||||
depth++
|
||||
}
|
||||
}
|
||||
require(depth==1) { "unbalanced RPN: $depth ${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
|
||||
|
||||
val leftDt = expr.left.type
|
||||
val rightDt = expr.right.type
|
||||
// see if we can apply some optimized routines still
|
||||
when(expr.operator) {
|
||||
|
||||
// compare with zero
|
||||
if(expr.operator in ComparisonOperators) {
|
||||
if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) {
|
||||
val rightVal = expr.right.asConstInteger()
|
||||
if(rightVal==0)
|
||||
return translateComparisonWithZero(expr.left, leftDt, expr.operator)
|
||||
}
|
||||
}
|
||||
|
||||
if(leftDt==DataType.STR && rightDt==DataType.STR && expr.operator in ComparisonOperators)
|
||||
return translateCompareStrings(expr.left, expr.operator, expr.right)
|
||||
|
||||
if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes)
|
||||
|| (leftDt in WordDatatypes && rightDt !in WordDatatypes))
|
||||
throw AssemblyError("binary operator ${expr.operator} left/right dt not identical")
|
||||
|
||||
// the general, non-optimized cases
|
||||
// TODO optimize more cases.... (or one day just don't use the evalstack at all anymore)
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(expr.right)
|
||||
when (leftDt) {
|
||||
in ByteDatatypes -> translateBinaryOperatorBytes(expr.operator, leftDt)
|
||||
in WordDatatypes -> translateBinaryOperatorWords(expr.operator, leftDt)
|
||||
DataType.FLOAT -> translateBinaryOperatorFloats(expr.operator)
|
||||
else -> throw AssemblyError("non-numerical datatype")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateSomewhatOptimized(left: PtExpression, operator: String, right: PtExpression): Boolean {
|
||||
val leftDt = left.type
|
||||
val rightDt = right.type
|
||||
when(operator) {
|
||||
"+" -> {
|
||||
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
||||
val leftVal = expr.left.asConstInteger()
|
||||
val rightVal = expr.right.asConstInteger()
|
||||
val leftVal = left.asConstInteger()
|
||||
val rightVal = right.asConstInteger()
|
||||
if (leftVal!=null && leftVal in -4..4) {
|
||||
translateExpressionInternal(expr.right)
|
||||
translateExpressionInternal(right)
|
||||
if(rightDt in ByteDatatypes) {
|
||||
val incdec = if(leftVal<0) "dec" else "inc"
|
||||
repeat(leftVal.absoluteValue) {
|
||||
@ -276,11 +378,11 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return true
|
||||
}
|
||||
else if (rightVal!=null && rightVal in -4..4)
|
||||
{
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
if(leftDt in ByteDatatypes) {
|
||||
val incdec = if(rightVal<0) "dec" else "inc"
|
||||
repeat(rightVal.absoluteValue) {
|
||||
@ -306,16 +408,16 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
"-" -> {
|
||||
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
||||
val rightVal = expr.right.asConstInteger()
|
||||
val rightVal = right.asConstInteger()
|
||||
if (rightVal!=null && rightVal in -4..4)
|
||||
{
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
if(leftDt in ByteDatatypes) {
|
||||
val incdec = if(rightVal<0) "inc" else "dec"
|
||||
repeat(rightVal.absoluteValue) {
|
||||
@ -341,14 +443,14 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
">>" -> {
|
||||
val amount = expr.right.asConstInteger()
|
||||
val amount = right.asConstInteger()
|
||||
if(amount!=null) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
when (leftDt) {
|
||||
DataType.UBYTE -> {
|
||||
if (amount <= 2)
|
||||
@ -374,17 +476,17 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" stz P8ESTACK_LO+1,x | stz P8ESTACK_HI+1,x")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta P8ESTACK_LO+1,x | sta P8ESTACK_HI+1,x")
|
||||
return
|
||||
return true
|
||||
}
|
||||
var left = amount
|
||||
while (left >= 7) {
|
||||
var amountLeft = amount
|
||||
while (amountLeft >= 7) {
|
||||
asmgen.out(" jsr math.shift_right_uw_7")
|
||||
left -= 7
|
||||
amountLeft -= 7
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" lsr P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
||||
if (amountLeft in 0..2)
|
||||
repeat(amountLeft) { asmgen.out(" lsr P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_right_uw_$left")
|
||||
asmgen.out(" jsr math.shift_right_uw_$amountLeft")
|
||||
}
|
||||
DataType.WORD -> {
|
||||
if(amount>=16) {
|
||||
@ -399,27 +501,27 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
sta P8ESTACK_LO+1,x
|
||||
sta P8ESTACK_HI+1,x
|
||||
+""")
|
||||
return
|
||||
return true
|
||||
}
|
||||
var left = amount
|
||||
while (left >= 7) {
|
||||
var amountLeft = amount
|
||||
while (amountLeft >= 7) {
|
||||
asmgen.out(" jsr math.shift_right_w_7")
|
||||
left -= 7
|
||||
amountLeft -= 7
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" lda P8ESTACK_HI+1,x | asl a | ror P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
||||
if (amountLeft in 0..2)
|
||||
repeat(amountLeft) { asmgen.out(" lda P8ESTACK_HI+1,x | asl a | ror P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_right_w_$left")
|
||||
asmgen.out(" jsr math.shift_right_w_$amountLeft")
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
"<<" -> {
|
||||
val amount = expr.right.asConstInteger()
|
||||
val amount = right.asConstInteger()
|
||||
if(amount!=null) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
if (leftDt in ByteDatatypes) {
|
||||
if (amount <= 2)
|
||||
repeat(amount) { asmgen.out(" asl P8ESTACK_LO+1,x") }
|
||||
@ -429,78 +531,80 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" sta P8ESTACK_LO+1,x")
|
||||
}
|
||||
} else {
|
||||
var left = amount
|
||||
while (left >= 7) {
|
||||
var amountLeft = amount
|
||||
while (amountLeft >= 7) {
|
||||
asmgen.out(" jsr math.shift_left_w_7")
|
||||
left -= 7
|
||||
amountLeft -= 7
|
||||
}
|
||||
if (left in 0..2)
|
||||
repeat(left) { asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") }
|
||||
if (amountLeft in 0..2)
|
||||
repeat(amountLeft) { asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") }
|
||||
else
|
||||
asmgen.out(" jsr math.shift_left_w_$left")
|
||||
asmgen.out(" jsr math.shift_left_w_$amountLeft")
|
||||
}
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
"*" -> {
|
||||
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
||||
val leftVar = expr.left as? PtIdentifier
|
||||
val rightVar = expr.right as? PtIdentifier
|
||||
if(leftVar!=null && rightVar!=null && leftVar==rightVar)
|
||||
return translateSquared(leftVar, leftDt)
|
||||
val leftVar = left as? PtIdentifier
|
||||
val rightVar = right as? PtIdentifier
|
||||
if(leftVar!=null && rightVar!=null && leftVar==rightVar) {
|
||||
translateSquared(leftVar, leftDt)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
val value = expr.right as? PtNumber
|
||||
val value = right as? PtNumber
|
||||
if(value!=null) {
|
||||
if(rightDt in IntegerDatatypes) {
|
||||
val amount = value.number.toInt()
|
||||
if(amount==2) {
|
||||
// optimize x*2 common case
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
if(leftDt in ByteDatatypes) {
|
||||
asmgen.out(" asl P8ESTACK_LO+1,x")
|
||||
} else {
|
||||
asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x")
|
||||
}
|
||||
return
|
||||
return true
|
||||
}
|
||||
when(rightDt) {
|
||||
DataType.UBYTE -> {
|
||||
if(amount in asmgen.optimizedByteMultiplications) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
asmgen.out(" jsr math.stack_mul_byte_$amount")
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
if(amount in asmgen.optimizedByteMultiplications) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
asmgen.out(" jsr math.stack_mul_byte_$amount")
|
||||
return
|
||||
return true
|
||||
}
|
||||
if(amount.absoluteValue in asmgen.optimizedByteMultiplications) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
asmgen.out(" jsr prog8_lib.neg_b | jsr math.stack_mul_byte_${amount.absoluteValue}")
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
if(amount in asmgen.optimizedWordMultiplications) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
asmgen.out(" jsr math.stack_mul_word_$amount")
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
DataType.WORD -> {
|
||||
if(amount in asmgen.optimizedWordMultiplications) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
asmgen.out(" jsr math.stack_mul_word_$amount")
|
||||
return
|
||||
return true
|
||||
}
|
||||
if(amount.absoluteValue in asmgen.optimizedWordMultiplications) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
asmgen.out(" jsr prog8_lib.neg_w | jsr math.stack_mul_word_${amount.absoluteValue}")
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
@ -510,9 +614,9 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
"/" -> {
|
||||
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
||||
val rightVal = expr.right.asConstInteger()
|
||||
val rightVal = right.asConstInteger()
|
||||
if(rightVal!=null && rightVal==2) {
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(left)
|
||||
when (leftDt) {
|
||||
DataType.UBYTE -> {
|
||||
asmgen.out(" lsr P8ESTACK_LO+1,x")
|
||||
@ -545,38 +649,13 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
in ComparisonOperators -> {
|
||||
if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) {
|
||||
val rightVal = expr.right.asConstInteger()
|
||||
if(rightVal==0)
|
||||
return translateComparisonWithZero(expr.left, leftDt, expr.operator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes)
|
||||
|| (leftDt in WordDatatypes && rightDt !in WordDatatypes))
|
||||
throw AssemblyError("binary operator ${expr.operator} left/right dt not identical")
|
||||
|
||||
if(leftDt==DataType.STR && rightDt==DataType.STR && expr.operator in ComparisonOperators) {
|
||||
translateCompareStrings(expr.left, expr.operator, expr.right)
|
||||
}
|
||||
else {
|
||||
// the general, non-optimized cases
|
||||
// TODO optimize more cases.... (or one day just don't use the evalstack at all anymore)
|
||||
translateExpressionInternal(expr.left)
|
||||
translateExpressionInternal(expr.right)
|
||||
when (leftDt) {
|
||||
in ByteDatatypes -> translateBinaryOperatorBytes(expr.operator, leftDt)
|
||||
in WordDatatypes -> translateBinaryOperatorWords(expr.operator, leftDt)
|
||||
DataType.FLOAT -> translateBinaryOperatorFloats(expr.operator)
|
||||
else -> throw AssemblyError("non-numerical datatype")
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun translateComparisonWithZero(expr: PtExpression, dt: DataType, operator: String) {
|
||||
@ -871,9 +950,13 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun translateCompareStrings(s1: PtExpression, operator: String, s2: PtExpression) {
|
||||
asmgen.assignExpressionToVariable(s1, "prog8_lib.strcmp_expression._arg_s1", DataType.UWORD, null)
|
||||
asmgen.assignExpressionToVariable(s2, "prog8_lib.strcmp_expression._arg_s2", DataType.UWORD, null)
|
||||
asmgen.assignExpressionToVariable(s1, "prog8_lib.strcmp_expression._arg_s1", DataType.UWORD)
|
||||
asmgen.assignExpressionToVariable(s2, "prog8_lib.strcmp_expression._arg_s2", DataType.UWORD)
|
||||
asmgen.out(" jsr prog8_lib.strcmp_expression") // result of compare is in A
|
||||
compareStringsProcessResultInA(operator)
|
||||
}
|
||||
|
||||
private fun compareStringsProcessResultInA(operator: String) {
|
||||
when(operator) {
|
||||
"==" -> asmgen.out(" and #1 | eor #1 | sta P8ESTACK_LO,x")
|
||||
"!=" -> asmgen.out(" and #1 | sta P8ESTACK_LO,x")
|
||||
|
@ -50,8 +50,8 @@ internal class ForLoopsAsmGen(private val program: PtProgram,
|
||||
val incdec = if(stepsize==1) "inc" else "dec"
|
||||
// loop over byte range via loopvar
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt), null)
|
||||
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt), null)
|
||||
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt))
|
||||
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt))
|
||||
asmgen.out(loopLabel)
|
||||
asmgen.translate(stmt.statements)
|
||||
asmgen.out("""
|
||||
@ -68,8 +68,8 @@ $modifiedLabel cmp #0 ; modified
|
||||
|
||||
// loop over byte range via loopvar
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt), null)
|
||||
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt), null)
|
||||
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt))
|
||||
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt))
|
||||
asmgen.out(loopLabel)
|
||||
asmgen.translate(stmt.statements)
|
||||
if(stepsize>0) {
|
||||
@ -594,6 +594,5 @@ $loopLabel""")
|
||||
asmgen.assignExpressionToVariable(
|
||||
range.from,
|
||||
asmgen.asmVariableName(stmt.variable),
|
||||
stmt.variable.type,
|
||||
stmt.definingISub())
|
||||
stmt.variable.type)
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
throw AssemblyError("argument type incompatible")
|
||||
|
||||
val varName = asmgen.asmVariableName(sub.scopedName + "." + parameter.name)
|
||||
asmgen.assignExpressionToVariable(value, varName, parameter.type, sub)
|
||||
asmgen.assignExpressionToVariable(value, varName, parameter.type)
|
||||
}
|
||||
|
||||
private fun argumentViaRegister(sub: IPtSubroutine, parameter: IndexedValue<PtSubroutineParameter>, value: PtExpression, registerOverride: RegisterOrPair? = null) {
|
||||
@ -198,16 +198,17 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
register!!
|
||||
if(requiredDt largerThan value.type) {
|
||||
// we need to sign extend the source, do this via temporary word variable
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", DataType.UBYTE, sub)
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", DataType.UBYTE)
|
||||
asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", value.type)
|
||||
asmgen.assignVariableToRegister("P8ZP_SCRATCH_W1", register, Position.DUMMY)
|
||||
asmgen.assignVariableToRegister("P8ZP_SCRATCH_W1", register, null, Position.DUMMY)
|
||||
} else {
|
||||
val scope = value.definingISub()
|
||||
val target: AsmAssignTarget =
|
||||
if(parameter.value.type in ByteDatatypes && (register==RegisterOrPair.AX || register == RegisterOrPair.AY || register==RegisterOrPair.XY || register in Cx16VirtualRegisters))
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, parameter.value.type, sub, value.position, register = register)
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, parameter.value.type, scope, value.position, register = register)
|
||||
else {
|
||||
val signed = parameter.value.type == DataType.BYTE || parameter.value.type == DataType.WORD
|
||||
AsmAssignTarget.fromRegisters(register, signed, value.position, sub, asmgen)
|
||||
AsmAssignTarget.fromRegisters(register, signed, value.position, scope, asmgen)
|
||||
}
|
||||
val src = if(value.type in PassByReferenceDatatypes) {
|
||||
if(value is PtIdentifier) {
|
||||
@ -221,7 +222,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
} else {
|
||||
AsmAssignSource.fromAstSource(value, program, asmgen).adjustSignedUnsigned(target)
|
||||
}
|
||||
asmgen.translateNormalAssignment(AsmAssignment(src, target, program.memsizer, Position.DUMMY))
|
||||
asmgen.translateNormalAssignment(AsmAssignment(src, target, program.memsizer, Position.DUMMY), scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,13 +359,18 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
asmgen.out("; variables")
|
||||
val asmGenInfo = asmgen.subroutineExtra(sub)
|
||||
// TODO move these to BSS as well
|
||||
for((dt, name, addr) in asmGenInfo.extraVars) {
|
||||
if(addr!=null)
|
||||
asmgen.out("$name = $addr")
|
||||
else when(dt) {
|
||||
DataType.UBYTE -> asmgen.out("$name .byte 0")
|
||||
DataType.UWORD -> asmgen.out("$name .word 0")
|
||||
else -> throw AssemblyError("weird dt")
|
||||
DataType.FLOAT -> {
|
||||
require(options.compTarget.machine.FLOAT_MEM_SIZE==5)
|
||||
asmgen.out("$name .byte 0,0,0,0,0")
|
||||
}
|
||||
else -> throw AssemblyError("weird dt for extravar $dt")
|
||||
}
|
||||
}
|
||||
if(asmGenInfo.usedRegsaveA) // will probably never occur
|
||||
|
@ -102,6 +102,28 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers)
|
||||
}
|
||||
}
|
||||
|
||||
fun isSameAs(left: PtExpression): Boolean =
|
||||
when(kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
val scopedName: String = if('.' in asmVarname)
|
||||
asmVarname
|
||||
else {
|
||||
val scopeName = (scope as? PtNamedNode)?.scopedName
|
||||
if (scopeName == null) asmVarname else "$scopeName.$asmVarname"
|
||||
}
|
||||
left is PtIdentifier && left.name==scopedName
|
||||
}
|
||||
TargetStorageKind.ARRAY -> {
|
||||
left is PtArrayIndexer && left isSameAs array!!
|
||||
}
|
||||
TargetStorageKind.MEMORY -> {
|
||||
left isSameAs memory!!
|
||||
}
|
||||
TargetStorageKind.REGISTER, TargetStorageKind.STACK -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
|
@ -1,13 +1,17 @@
|
||||
package prog8.codegen.cpu6502.assignment
|
||||
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.codegen.cpu6502.AsmGen6502Internal
|
||||
import prog8.codegen.cpu6502.VariableAllocator
|
||||
import prog8.codegen.cpu6502.returnsWhatWhere
|
||||
import java.util.*
|
||||
|
||||
|
||||
internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
private val symbolTable: SymbolTable,
|
||||
private val asmgen: AsmGen6502Internal,
|
||||
private val allocator: VariableAllocator) {
|
||||
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator)
|
||||
@ -16,17 +20,17 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
val target = AsmAssignTarget.fromAstAssignment(assignment.target, assignment.definingISub(), asmgen)
|
||||
val source = AsmAssignSource.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target)
|
||||
val assign = AsmAssignment(source, target, program.memsizer, assignment.position)
|
||||
translateNormalAssignment(assign)
|
||||
translateNormalAssignment(assign, assignment.definingISub())
|
||||
}
|
||||
|
||||
fun translate(augmentedAssign: PtAugmentedAssign) {
|
||||
val target = AsmAssignTarget.fromAstAssignment(augmentedAssign.target, augmentedAssign.definingISub(), asmgen)
|
||||
val source = AsmAssignSource.fromAstSource(augmentedAssign.value, program, asmgen).adjustSignedUnsigned(target)
|
||||
val assign = AsmAugmentedAssignment(source, augmentedAssign.operator, target, program.memsizer, augmentedAssign.position)
|
||||
augmentableAsmGen.translate(assign)
|
||||
augmentableAsmGen.translate(assign, augmentedAssign.definingISub())
|
||||
}
|
||||
|
||||
fun translateNormalAssignment(assign: AsmAssignment) {
|
||||
fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||
when(assign.source.kind) {
|
||||
SourceStorageKind.LITERALNUMBER -> {
|
||||
// simple case: assign a constant number
|
||||
@ -127,7 +131,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
SourceStorageKind.MEMORY -> {
|
||||
fun assignViaExprEval(expression: PtExpression) {
|
||||
assignExpressionToVariable(expression, "P8ZP_SCRATCH_W2", DataType.UWORD, assign.target.scope)
|
||||
assignExpressionToVariable(expression, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2")
|
||||
assignRegisterByte(assign.target, CpuRegister.A)
|
||||
}
|
||||
@ -141,8 +145,17 @@ 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 -> {
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(value.address as PtBinaryExpression, false)) {
|
||||
val addrExpr = value.address as PtBinaryExpression
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
|
||||
assignRegisterByte(assign.target, CpuRegister.A)
|
||||
} else {
|
||||
assignViaExprEval(value.address)
|
||||
@ -152,7 +165,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
assignExpression(assign)
|
||||
assignExpression(assign, scope)
|
||||
}
|
||||
SourceStorageKind.REGISTER -> {
|
||||
asmgen.assignRegister(assign.source.register!!, assign.target)
|
||||
@ -164,7 +177,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignExpression(assign: AsmAssignment) {
|
||||
private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||
when(val value = assign.source.expression!!) {
|
||||
is PtAddressOf -> {
|
||||
val sourceName = asmgen.asmSymbolName(value.identifier)
|
||||
@ -277,17 +290,17 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
AsmAssignment(
|
||||
AsmAssignSource.fromAstSource(value.value, program, asmgen),
|
||||
assign.target, program.memsizer, assign.position
|
||||
)
|
||||
), scope
|
||||
)
|
||||
when (value.operator) {
|
||||
"+" -> {}
|
||||
"-" -> inplaceNegate(assign, true)
|
||||
"~" -> inplaceInvert(assign)
|
||||
"-" -> inplaceNegate(assign, true, scope)
|
||||
"~" -> inplaceInvert(assign, scope)
|
||||
"not" -> throw AssemblyError("not should have been replaced in the Ast by ==0")
|
||||
else -> throw AssemblyError("invalid prefix operator")
|
||||
}
|
||||
} else {
|
||||
assignPrefixedExpressionToArrayElt(assign)
|
||||
assignPrefixedExpressionToArrayElt(assign, scope)
|
||||
}
|
||||
}
|
||||
is PtContainmentCheck -> {
|
||||
@ -295,6 +308,7 @@ 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,
|
||||
@ -302,11 +316,20 @@ 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")
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignPrefixedExpressionToArrayElt(assign: AsmAssignment) {
|
||||
private fun assignPrefixedExpressionToArrayElt(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||
require(assign.source.expression is PtPrefix)
|
||||
if(assign.source.datatype==DataType.FLOAT) {
|
||||
// floatarray[x] = -value ... just use FAC1 to calculate the expression into and then store that back into the array.
|
||||
@ -318,7 +341,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
val assignToTempvar = AsmAssignment(assign.source,
|
||||
AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, assign.target.datatype, assign.target.scope, assign.target.position,
|
||||
variableAsmName=tempvar, origAstTarget = assign.target.origAstTarget), program.memsizer, assign.position)
|
||||
asmgen.translateNormalAssignment(assignToTempvar)
|
||||
asmgen.translateNormalAssignment(assignToTempvar, scope)
|
||||
when(assign.target.datatype) {
|
||||
in ByteDatatypes -> assignVariableByte(assign.target, tempvar)
|
||||
in WordDatatypes -> assignVariableWord(assign.target, tempvar)
|
||||
@ -339,6 +362,253 @@ 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.operator in ComparisonOperators) {
|
||||
assignRPNComparison(assign, value)
|
||||
return true
|
||||
}
|
||||
|
||||
if(value.children.size==3 && left is PtExpression && right is PtExpression)
|
||||
if(simpleLogicalExprRPN(left, oper.operator, right, assign.target))
|
||||
return true
|
||||
|
||||
// TODO RPN add +,-,<<,>> and perhaps even == and != special behaviors of BinExpr
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
var depth=0
|
||||
value.children.forEach {
|
||||
when (it) {
|
||||
is PtRpnOperator -> {
|
||||
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++
|
||||
symbolTable.resetCachedFlat()
|
||||
if(it.operator in ComparisonOperators) {
|
||||
require(it.type == DataType.UBYTE)
|
||||
val scopeName = (scope as PtNamedNode).scopedName
|
||||
val comparison = PtRpn(DataType.UBYTE, assign.position)
|
||||
comparison.addRpnNode(PtIdentifier("$scopeName.$leftvar", it.type, value.position))
|
||||
comparison.addRpnNode(PtIdentifier("$scopeName.$rightvar", it.rightType, value.position))
|
||||
comparison.addRpnNode(PtRpnOperator(it.operator, it.type, it.leftType, it.rightType, it.position))
|
||||
comparison.parent = scope
|
||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = comparison)
|
||||
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, scope, assign.position, variableAsmName = resultVarname)
|
||||
val normalAssign = AsmAssignment(src, target, program.memsizer, assign.position)
|
||||
assignRPNComparison(normalAssign, comparison)
|
||||
} else {
|
||||
require(resultVarname==leftvar) {
|
||||
"expected result $resultVarname == leftvar $leftvar"
|
||||
}
|
||||
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 augAssign = AsmAugmentedAssignment(src, it.operator+"=", target, program.memsizer, assign.position)
|
||||
augmentableAsmGen.translate(augAssign, scope)
|
||||
}
|
||||
}
|
||||
is PtExpression -> {
|
||||
val varname = evalVarName(it.type, depth)
|
||||
assignExpressionToVariable(it, varname, it.type)
|
||||
depth++
|
||||
}
|
||||
else -> throw AssemblyError("weird rpn node")
|
||||
}
|
||||
}
|
||||
require(depth==1) { "unbalanced RPN: $depth ${value.position}" }
|
||||
val resultVariable = evalVars.getValue(getVarDt(value.type)).pop()
|
||||
when(assign.target.datatype) {
|
||||
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 simpleLogicalExprRPN(left: PtExpression, operator: String, right: PtExpression, target: AsmAssignTarget): Boolean {
|
||||
fun simpleLogicalBytesExpr() {
|
||||
// both left and right expression operands are simple.
|
||||
if (right is PtNumber || right is PtIdentifier)
|
||||
assignLogicalWithSimpleRightOperandByte(target, left, operator, right)
|
||||
else if (left is PtNumber || left is PtIdentifier)
|
||||
assignLogicalWithSimpleRightOperandByte(target, right, operator, left)
|
||||
else {
|
||||
assignExpressionToRegister(left, RegisterOrPair.A, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.A, false)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||
when (operator) {
|
||||
"&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1")
|
||||
"|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1")
|
||||
"^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_B1")
|
||||
else -> throw AssemblyError("invalid operator")
|
||||
}
|
||||
assignRegisterByte(target, CpuRegister.A)
|
||||
}
|
||||
}
|
||||
|
||||
fun simpleLogicalWordsExpr() {
|
||||
// both left and right expression operands are simple.
|
||||
if (right is PtNumber || right is PtIdentifier)
|
||||
assignLogicalWithSimpleRightOperandWord(target, left, operator, right)
|
||||
else if (left is PtNumber || left is PtIdentifier)
|
||||
assignLogicalWithSimpleRightOperandWord(target, right, operator, left)
|
||||
else {
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.A, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
||||
assignExpressionToVariable(right, "P8ZP_SCRATCH_W1", DataType.UWORD)
|
||||
when (operator) {
|
||||
"&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1")
|
||||
"|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1")
|
||||
"^", "xor" -> asmgen.out(" pla | eor P8ZP_SCRATCH_W1+1 | tay | pla | eor P8ZP_SCRATCH_W1")
|
||||
else -> throw AssemblyError("invalid operator")
|
||||
}
|
||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
}
|
||||
}
|
||||
|
||||
if(operator in setOf("&", "|", "^", "and", "or", "xor")) {
|
||||
if (left.type in ByteDatatypes && right.type in ByteDatatypes) {
|
||||
if (right.isSimple()) {
|
||||
simpleLogicalBytesExpr()
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (left.type in WordDatatypes && right.type in WordDatatypes) {
|
||||
if (right.isSimple()) {
|
||||
simpleLogicalWordsExpr()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun assignRPNComparison(assign: AsmAssignment, comparison: PtRpn) {
|
||||
val (leftRpn, oper, right) = comparison.finalOperation()
|
||||
val constRight = (right as PtExpression).asConstInteger()
|
||||
if(constRight == 0) {
|
||||
if(oper.operator == "==" || oper.operator == "!=") {
|
||||
when(assign.target.datatype) {
|
||||
in ByteDatatypes -> {
|
||||
if(attemptAssignToByteCompareZeroRPN(comparison, assign))
|
||||
return
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
assignConstantWord(assign.target, 0)
|
||||
if(attemptAssignToByteCompareZeroRPN(comparison, assign))
|
||||
return
|
||||
}
|
||||
else -> {
|
||||
// do nothing, this is handled by a type cast.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val left: PtExpression = if(comparison.children.size>3 || leftRpn !is PtExpression) {
|
||||
comparison.children.removeLast()
|
||||
comparison.children.removeLast()
|
||||
comparison
|
||||
} else
|
||||
leftRpn
|
||||
|
||||
val leftNum = left as? PtNumber
|
||||
val rightNum = right as? PtNumber
|
||||
val jumpIfFalseLabel = asmgen.makeLabel("cmp")
|
||||
|
||||
if(assign.target.isSameAs(left)) {
|
||||
// In-place comparison Target = Target <compare> Right
|
||||
val targetDt = assign.target.datatype
|
||||
val tempVar = asmgen.getTempVarName(assign.target.datatype)
|
||||
val tempTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, targetDt, comparison.definingISub(), comparison.position, variableAsmName = tempVar)
|
||||
when (assign.target.datatype) {
|
||||
in ByteDatatypes -> assignConstantByte(tempTarget, 0)
|
||||
in WordDatatypes -> assignConstantWord(tempTarget, 0)
|
||||
DataType.FLOAT -> assignConstantFloat(tempTarget, 0.0)
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum)
|
||||
when (assign.target.datatype) {
|
||||
in ByteDatatypes -> assignConstantByte(tempTarget, 1)
|
||||
in WordDatatypes -> assignConstantWord(tempTarget, 1)
|
||||
DataType.FLOAT -> assignConstantFloat(tempTarget, 1.0)
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
asmgen.out(jumpIfFalseLabel)
|
||||
val tempLeft = PtIdentifier(tempVar, targetDt, comparison.position)
|
||||
tempLeft.parent=comparison
|
||||
asmgen.assignExpressionTo(tempLeft, assign.target)
|
||||
} else {
|
||||
// Normal comparison Target = Left <compare> Right
|
||||
when (assign.target.datatype) {
|
||||
in ByteDatatypes -> assignConstantByte(assign.target, 0)
|
||||
in WordDatatypes -> assignConstantWord(assign.target, 0)
|
||||
DataType.FLOAT -> assignConstantFloat(assign.target, 0.0)
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum)
|
||||
when (assign.target.datatype) {
|
||||
in ByteDatatypes -> assignConstantByte(assign.target, 1)
|
||||
in WordDatatypes -> assignConstantWord(assign.target, 1)
|
||||
DataType.FLOAT -> assignConstantFloat(assign.target, 1.0)
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
asmgen.out(jumpIfFalseLabel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||
if(expr.operator in ComparisonOperators) {
|
||||
if(expr.right.asConstInteger() == 0) {
|
||||
@ -384,7 +654,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
else {
|
||||
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.A, false)
|
||||
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingISub())
|
||||
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||
when (expr.operator) {
|
||||
"&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1")
|
||||
@ -406,7 +676,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
assignExpressionToRegister(expr.left, RegisterOrPair.AY, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.A, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
||||
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingISub())
|
||||
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD)
|
||||
when (expr.operator) {
|
||||
"&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1")
|
||||
"|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1")
|
||||
@ -439,7 +709,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
expr.left.isSimple() && expr.right.isSimple()) {
|
||||
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.A, false)
|
||||
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingISub())
|
||||
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||
if(expr.operator=="==") {
|
||||
asmgen.out("""
|
||||
@ -465,7 +735,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
assignExpressionToRegister(expr.left, RegisterOrPair.AY, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.A, false)
|
||||
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
||||
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingISub())
|
||||
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||
if(expr.operator=="==") {
|
||||
@ -721,6 +991,84 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
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.children.removeLast()
|
||||
expr.children.removeLast()
|
||||
expr
|
||||
} 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) {
|
||||
"==" -> {
|
||||
@ -836,7 +1184,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
return
|
||||
}
|
||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
||||
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt, containment.definingISub())
|
||||
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt)
|
||||
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W2"), varname)
|
||||
asmgen.out(" ldy #$numElements")
|
||||
asmgen.out(" jsr prog8_lib.containment_wordarray")
|
||||
@ -886,7 +1234,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
if(targetDt in WordDatatypes) {
|
||||
|
||||
fun assignViaExprEval(addressExpression: PtExpression) {
|
||||
asmgen.assignExpressionToVariable(addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
asmgen.assignExpressionToVariable(addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2")
|
||||
asmgen.out(" ldy #0")
|
||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
@ -900,8 +1248,18 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
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 -> {
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(value.address as PtBinaryExpression, false)) {
|
||||
val addrExpr = value.address as PtBinaryExpression
|
||||
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
|
||||
asmgen.out(" ldy #0")
|
||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
} else {
|
||||
@ -940,7 +1298,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
in PassByReferenceDatatypes -> {
|
||||
// str/array value cast (most likely to UWORD, take address-of)
|
||||
assignExpressionToVariable(value, target.asmVarname, targetDt, null)
|
||||
assignExpressionToVariable(value, target.asmVarname, targetDt)
|
||||
}
|
||||
else -> throw AssemblyError("strange dt in typecast assign to var: $valueDt --> $targetDt")
|
||||
}
|
||||
@ -998,7 +1356,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
// have to typecast the float number on the fly down to an integer
|
||||
assignExpressionToRegister(value, RegisterOrPair.FAC1, target.datatype in SignedDatatypes)
|
||||
assignTypeCastedFloatFAC1("P8ZP_SCRATCH_W1", target.datatype)
|
||||
assignVariableToRegister("P8ZP_SCRATCH_W1", target.register!!, target.datatype in SignedDatatypes, target.position)
|
||||
assignVariableToRegister("P8ZP_SCRATCH_W1", target.register!!, target.datatype in SignedDatatypes, origTypeCastExpression.definingISub(), target.position)
|
||||
return
|
||||
} else {
|
||||
if(!(valueDt isAssignableTo targetDt)) {
|
||||
@ -1103,7 +1461,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
lsb.add(value)
|
||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb)
|
||||
val assign = AsmAssignment(src, target, program.memsizer, value.position)
|
||||
translateNormalAssignment(assign)
|
||||
translateNormalAssignment(assign, value.definingISub())
|
||||
}
|
||||
|
||||
private fun assignTypeCastedFloatFAC1(targetAsmVarName: String, targetDt: DataType) {
|
||||
@ -2801,13 +3159,13 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
fun storeViaExprEval() {
|
||||
when(addressExpr) {
|
||||
is PtNumber, is PtIdentifier -> {
|
||||
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2")
|
||||
}
|
||||
else -> {
|
||||
// same as above but we need to save the A register
|
||||
asmgen.out(" pha")
|
||||
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
asmgen.out(" pla")
|
||||
asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2")
|
||||
}
|
||||
@ -2821,8 +3179,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
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, true))
|
||||
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
|
||||
storeViaExprEval()
|
||||
}
|
||||
else -> storeViaExprEval()
|
||||
@ -2833,28 +3195,28 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
|
||||
val tgt = AsmAssignTarget.fromRegisters(register, signed, expr.position, null, asmgen)
|
||||
val assign = AsmAssignment(src, tgt, program.memsizer, expr.position)
|
||||
translateNormalAssignment(assign)
|
||||
translateNormalAssignment(assign, expr.definingISub())
|
||||
}
|
||||
|
||||
internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType, scope: IPtSubroutine?) {
|
||||
internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType) {
|
||||
if(expr.type==DataType.FLOAT && dt!=DataType.FLOAT) {
|
||||
throw AssemblyError("can't directly assign a FLOAT expression to an integer variable $expr")
|
||||
} else {
|
||||
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
|
||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, scope, expr.position, variableAsmName = asmVarName)
|
||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, expr.definingISub(), expr.position, variableAsmName = asmVarName)
|
||||
val assign = AsmAssignment(src, tgt, program.memsizer, expr.position)
|
||||
translateNormalAssignment(assign)
|
||||
translateNormalAssignment(assign, expr.definingISub())
|
||||
}
|
||||
}
|
||||
|
||||
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, signed: Boolean, pos: Position) {
|
||||
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, signed: Boolean, scope: IPtSubroutine?, pos: Position) {
|
||||
val tgt = AsmAssignTarget.fromRegisters(register, signed, pos, null, asmgen)
|
||||
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, tgt.datatype, variableAsmName = asmVarName)
|
||||
val assign = AsmAssignment(src, tgt, program.memsizer, Position.DUMMY)
|
||||
translateNormalAssignment(assign)
|
||||
translateNormalAssignment(assign, scope)
|
||||
}
|
||||
|
||||
internal fun inplaceInvert(assign: AsmAssignment) {
|
||||
internal fun inplaceInvert(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||
val target = assign.target
|
||||
when (assign.target.datatype) {
|
||||
DataType.UBYTE -> {
|
||||
@ -2881,7 +3243,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" sta ($sourceName),y")
|
||||
}
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(memory.address, "P8ZP_SCRATCH_W2", DataType.UWORD, target.scope)
|
||||
asmgen.assignExpressionToVariable(memory.address, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
asmgen.out("""
|
||||
ldy #0
|
||||
lda (P8ZP_SCRATCH_W2),y
|
||||
@ -2899,7 +3261,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
TargetStorageKind.STACK -> TODO("no asm gen for byte stack invert")
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("~", assign))
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("~", assign), scope)
|
||||
else -> throw AssemblyError("weird target")
|
||||
}
|
||||
}
|
||||
@ -2924,7 +3286,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
TargetStorageKind.STACK -> TODO("no asm gen for word stack invert")
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("~", assign))
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("~", assign), scope)
|
||||
else -> throw AssemblyError("weird target")
|
||||
}
|
||||
}
|
||||
@ -2932,7 +3294,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
internal fun inplaceNegate(assign: AsmAssignment, ignoreDatatype: Boolean) {
|
||||
internal fun inplaceNegate(assign: AsmAssignment, ignoreDatatype: Boolean, scope: IPtSubroutine?) {
|
||||
val target = assign.target
|
||||
val datatype = if(ignoreDatatype) {
|
||||
when(target.datatype) {
|
||||
@ -2967,7 +3329,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that")
|
||||
TargetStorageKind.STACK -> TODO("no asm gen for byte stack negate")
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign))
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope)
|
||||
else -> throw AssemblyError("weird target")
|
||||
}
|
||||
}
|
||||
@ -3027,7 +3389,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that")
|
||||
TargetStorageKind.STACK -> TODO("no asm gen for word stack negate")
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign))
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope)
|
||||
else -> throw AssemblyError("weird target")
|
||||
}
|
||||
}
|
||||
@ -3049,7 +3411,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
||||
""")
|
||||
}
|
||||
TargetStorageKind.STACK -> TODO("no asm gen for float stack negate")
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign))
|
||||
TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope)
|
||||
else -> throw AssemblyError("weird target for in-place float negation")
|
||||
}
|
||||
}
|
||||
|
@ -11,16 +11,16 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
private val asmgen: AsmGen6502Internal,
|
||||
private val allocator: VariableAllocator
|
||||
) {
|
||||
fun translate(assign: AsmAugmentedAssignment) {
|
||||
fun translate(assign: AsmAugmentedAssignment, scope: IPtSubroutine?) {
|
||||
|
||||
when(assign.operator) {
|
||||
"-" -> {
|
||||
val a2 = AsmAssignment(assign.source, assign.target, assign.memsizer, assign.position)
|
||||
assignmentAsmGen.inplaceNegate(a2, false)
|
||||
assignmentAsmGen.inplaceNegate(a2, false, scope)
|
||||
}
|
||||
"~" -> {
|
||||
val a2 = AsmAssignment(assign.source, assign.target, assign.memsizer, assign.position)
|
||||
assignmentAsmGen.inplaceInvert(a2)
|
||||
assignmentAsmGen.inplaceInvert(a2, scope)
|
||||
}
|
||||
"+" -> { /* is a nop */ }
|
||||
else -> {
|
||||
@ -44,6 +44,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
"^=" -> inplaceModification(assign.target, "^", srcValue)
|
||||
"<<=" -> inplaceModification(assign.target, "<<", srcValue)
|
||||
">>=" -> inplaceModification(assign.target, ">>", srcValue)
|
||||
"%=" -> inplaceModification(assign.target, "%", srcValue)
|
||||
else -> throw AssemblyError("invalid augmented assign operator ${assign.operator}")
|
||||
}
|
||||
}
|
||||
@ -303,7 +304,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun inplaceModification_byte_value_to_pointer(pointervar: PtIdentifier, operator: String, value: PtExpression) {
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
val sourceName = asmgen.loadByteFromPointerIntoA(pointervar)
|
||||
when (operator) {
|
||||
// note: ** (power) operator requires floats.
|
||||
@ -453,7 +454,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" clc | adc $name | sta $name")
|
||||
}
|
||||
"-" -> {
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", dt, null)
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", dt)
|
||||
asmgen.out(" lda $name | sec | sbc P8ZP_SCRATCH_B1 | sta $name")
|
||||
}
|
||||
"*" -> {
|
||||
@ -1358,7 +1359,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
when (operator) {
|
||||
// note: ** (power) operator requires floats.
|
||||
"+" -> {
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", valueDt, null)
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", valueDt)
|
||||
if(valueDt==DataType.UBYTE)
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
@ -1382,7 +1383,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
sta $name+1""")
|
||||
}
|
||||
"-" -> {
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", valueDt, null)
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", valueDt)
|
||||
if(valueDt==DataType.UBYTE)
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
@ -1488,7 +1489,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" clc | adc $name | sta $name | tya | adc $name+1 | sta $name+1")
|
||||
}
|
||||
"-" -> {
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", valueDt, null)
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", valueDt)
|
||||
asmgen.out(" lda $name | sec | sbc P8ZP_SCRATCH_W1 | sta $name | lda $name+1 | sbc P8ZP_SCRATCH_W1+1 | sta $name+1")
|
||||
}
|
||||
"*" -> {
|
||||
|
@ -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
|
||||
|
||||
@ -16,6 +13,12 @@ class ExperiCodeGen: 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)
|
||||
}
|
||||
|
||||
// you could write a code generator directly on the PtProgram AST,
|
||||
// but you can also use the Intermediate Representation to build a codegen on:
|
||||
val irCodeGen = IRCodeGen(program, symbolTable, options, errors)
|
||||
|
@ -92,10 +92,19 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
value.add(origAssign.value)
|
||||
} else {
|
||||
require(origAssign.operator.endsWith('='))
|
||||
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
|
||||
val left: PtExpression = origAssign.target.children.single() as PtExpression
|
||||
value.add(left)
|
||||
value.add(origAssign.value)
|
||||
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))
|
||||
} else {
|
||||
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
|
||||
val left: PtExpression = origAssign.target.children.single() as PtExpression
|
||||
value.add(left)
|
||||
value.add(origAssign.value)
|
||||
}
|
||||
}
|
||||
normalAssign.add(value)
|
||||
return translateRegularAssign(normalAssign)
|
||||
@ -262,9 +271,19 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val tr = if(itemsize==1) {
|
||||
expressionEval.translateExpression(array.index)
|
||||
} else {
|
||||
val mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
mult.children += array.index
|
||||
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
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))
|
||||
} else {
|
||||
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
mult.children += array.index
|
||||
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
}
|
||||
expressionEval.translateExpression(mult)
|
||||
}
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
|
@ -93,6 +93,7 @@ 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)
|
||||
@ -315,6 +316,10 @@ 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
|
||||
@ -615,28 +620,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(codeGen.isOne(operand)) {
|
||||
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
|
||||
val ins = if(knownAddress!=null)
|
||||
IRInstruction(opc, vmDt, value=knownAddress)
|
||||
else
|
||||
IRInstruction(opc, vmDt, labelSymbol = symbol)
|
||||
addInstr(result, ins, null)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
|
||||
val ins = if(knownAddress!=null)
|
||||
IRInstruction(opc, vmDt, reg1 = tr.resultReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(opc, vmDt, reg1 = tr.resultReg, labelSymbol = symbol)
|
||||
addInstr(result, ins, null)
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: IRDataType): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
return if(codeGen.isOne(binExpr.right)){
|
||||
@ -654,26 +637,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(codeGen.isOne(operand)){
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.LSLM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol)
|
||||
, null)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
,null)
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
private fun operatorXor(binExpr: PtBinaryExpression, vmDt: IRDataType): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
return if(binExpr.right is PtNumber) {
|
||||
@ -691,18 +654,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
,null)
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: IRDataType): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
return if(binExpr.right is PtNumber) {
|
||||
@ -720,18 +671,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
,null)
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
private fun operatorOr(binExpr: PtBinaryExpression, vmDt: IRDataType): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
return if(binExpr.right is PtNumber) {
|
||||
@ -749,18 +688,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
, null)
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: IRDataType): ExpressionCodeResult {
|
||||
require(vmDt!=IRDataType.FLOAT) {"floating-point modulo not supported ${binExpr.position}"}
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
@ -834,55 +761,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
result += codeGen.divideByConstFloatInplace(knownAddress, symbol, factor)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
val ins = if(signed) {
|
||||
if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol)
|
||||
}
|
||||
addInstr(result, ins, null)
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
result += codeGen.divideByConstInplace(vmDt, knownAddress, symbol, factor, signed)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val ins = if(signed) {
|
||||
if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol)
|
||||
}
|
||||
addInstr(result, ins, null)
|
||||
}
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: IRDataType): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constFactorLeft = binExpr.left as? PtNumber
|
||||
@ -932,39 +810,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
result += codeGen.multiplyByConstFloatInplace(knownAddress, symbol, factor)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
result += codeGen.multiplyByConstInplace(vmDt, knownAddress, symbol, factor)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: IRDataType): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
@ -1014,46 +859,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
} else {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: IRDataType): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
@ -1115,6 +920,153 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
,null)
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
, null)
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
result += codeGen.divideByConstFloatInplace(knownAddress, symbol, factor)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
val ins = if(signed) {
|
||||
if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol)
|
||||
}
|
||||
addInstr(result, ins, null)
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
result += codeGen.divideByConstInplace(vmDt, knownAddress, symbol, factor, signed)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val ins = if(signed) {
|
||||
if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVSM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol)
|
||||
}
|
||||
addInstr(result, ins, null)
|
||||
}
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
result += codeGen.multiplyByConstFloatInplace(knownAddress, symbol, factor)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.MULM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
result += codeGen.multiplyByConstInplace(vmDt, knownAddress, symbol, factor)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.MULM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.SUBM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
} else {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.SUBM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
, null)
|
||||
}
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
@ -1155,6 +1107,60 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(codeGen.isOne(operand)) {
|
||||
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
|
||||
val ins = if(knownAddress!=null)
|
||||
IRInstruction(opc, vmDt, value=knownAddress)
|
||||
else
|
||||
IRInstruction(opc, vmDt, labelSymbol = symbol)
|
||||
addInstr(result, ins, null)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
|
||||
val ins = if(knownAddress!=null)
|
||||
IRInstruction(opc, vmDt, reg1 = tr.resultReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(opc, vmDt, reg1 = tr.resultReg, labelSymbol = symbol)
|
||||
addInstr(result, ins, null)
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(codeGen.isOne(operand)){
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.LSLM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol)
|
||||
, null)
|
||||
} else {
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
,null)
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(knownAddress!=null)
|
||||
IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
,null)
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -269,6 +269,8 @@ class IRCodeGen(
|
||||
is PtProgram,
|
||||
is PtArrayIndexer,
|
||||
is PtBinaryExpression,
|
||||
is PtRpn,
|
||||
is PtRpnOperator,
|
||||
is PtIdentifier,
|
||||
is PtWhenChoice,
|
||||
is PtPrefix,
|
||||
@ -896,30 +898,70 @@ class IRCodeGen(
|
||||
|
||||
private fun translate(ifElse: PtIfElse): IRCodeChunks {
|
||||
val condition = ifElse.condition
|
||||
if(condition.operator !in ComparisonOperators)
|
||||
throw AssemblyError("if condition should only be a binary comparison expression")
|
||||
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val irDtLeft = irType(condition.left.type)
|
||||
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
|
||||
return when {
|
||||
goto!=null && ifElse.elseScope.children.isEmpty() -> translateIfFollowedByJustGoto(ifElse, goto, irDtLeft, signed)
|
||||
constValue(condition.right) == 0.0 -> translateIfElseZeroComparison(ifElse, irDtLeft, signed)
|
||||
else -> translateIfElseNonZeroComparison(ifElse, irDtLeft, signed)
|
||||
when (condition) {
|
||||
is PtBinaryExpression -> {
|
||||
if(condition.operator !in ComparisonOperators)
|
||||
throw AssemblyError("if condition should only be a binary comparison expression")
|
||||
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val irDtLeft = irType(condition.left.type)
|
||||
return when {
|
||||
goto!=null && ifElse.elseScope.children.isEmpty() -> translateIfFollowedByJustGoto(ifElse, goto, irDtLeft, signed)
|
||||
constValue(condition.right) == 0.0 -> translateIfElseZeroComparison(ifElse, irDtLeft, signed)
|
||||
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) {
|
||||
val leftTr = expressionEval.translateExpression(ifElse.condition.left)
|
||||
if (irDtLeft == IRDataType.FLOAT) {
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, -1, leftTr.resultFpReg)
|
||||
val rightTr = expressionEval.translateExpression(ifElse.condition.right)
|
||||
val rightTr = expressionEval.translateExpression(condition.right)
|
||||
addToResult(result, rightTr, -1, rightTr.resultFpReg)
|
||||
result += IRCodeChunk(null,null).also {
|
||||
result += IRCodeChunk(null, null).also {
|
||||
val compResultReg = registers.nextFree()
|
||||
it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=compResultReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightTr.resultFpReg)
|
||||
val gotoOpcode = when (ifElse.condition.operator) {
|
||||
it += IRInstruction(
|
||||
Opcode.FCOMP,
|
||||
IRDataType.FLOAT,
|
||||
reg1 = compResultReg,
|
||||
fpReg1 = leftTr.resultFpReg,
|
||||
fpReg2 = rightTr.resultFpReg
|
||||
)
|
||||
val gotoOpcode = when (condition.operator) {
|
||||
"==" -> Opcode.BZ
|
||||
"!=" -> Opcode.BNZ
|
||||
"<" -> Opcode.BLEZS
|
||||
@ -929,16 +971,31 @@ class IRCodeGen(
|
||||
else -> throw AssemblyError("weird operator")
|
||||
}
|
||||
it += if (goto.address != null)
|
||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, value = goto.address?.toInt())
|
||||
IRInstruction(
|
||||
gotoOpcode,
|
||||
IRDataType.BYTE,
|
||||
reg1 = compResultReg,
|
||||
value = goto.address?.toInt()
|
||||
)
|
||||
else if (goto.generatedLabel != null)
|
||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, labelSymbol = goto.generatedLabel)
|
||||
IRInstruction(
|
||||
gotoOpcode,
|
||||
IRDataType.BYTE,
|
||||
reg1 = compResultReg,
|
||||
labelSymbol = goto.generatedLabel
|
||||
)
|
||||
else
|
||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, labelSymbol = goto.identifier!!.name)
|
||||
IRInstruction(
|
||||
gotoOpcode,
|
||||
IRDataType.BYTE,
|
||||
reg1 = compResultReg,
|
||||
labelSymbol = goto.identifier!!.name
|
||||
)
|
||||
}
|
||||
return result
|
||||
} else {
|
||||
val rightConst = ifElse.condition.right.asConstInteger()
|
||||
return if(rightConst==0)
|
||||
val rightConst = condition.right.asConstInteger()
|
||||
return if (rightConst == 0)
|
||||
ifZeroIntThenJump(result, ifElse, signed, irDtLeft, goto)
|
||||
else {
|
||||
ifNonZeroIntThenJump(result, ifElse, signed, irDtLeft, goto)
|
||||
@ -953,9 +1010,11 @@ class IRCodeGen(
|
||||
irDtLeft: IRDataType,
|
||||
goto: PtJump
|
||||
): MutableList<IRCodeChunkBase> {
|
||||
val leftTr = expressionEval.translateExpression(ifElse.condition.left)
|
||||
require(!program.binaryExpressionsAreRPN)
|
||||
val condition = ifElse.condition as PtBinaryExpression
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val opcode = when (ifElse.condition.operator) {
|
||||
val opcode = when (condition.operator) {
|
||||
"==" -> Opcode.BZ
|
||||
"!=" -> Opcode.BNZ
|
||||
"<" -> if (signed) Opcode.BLZS else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
|
||||
@ -980,14 +1039,16 @@ class IRCodeGen(
|
||||
irDtLeft: IRDataType,
|
||||
goto: PtJump
|
||||
): MutableList<IRCodeChunkBase> {
|
||||
val leftTr = expressionEval.translateExpression(ifElse.condition.left)
|
||||
require(!program.binaryExpressionsAreRPN)
|
||||
val condition = ifElse.condition as PtBinaryExpression
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val rightTr = expressionEval.translateExpression(ifElse.condition.right)
|
||||
val rightTr = expressionEval.translateExpression(condition.right)
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
val opcode: Opcode
|
||||
val firstReg: Int
|
||||
val secondReg: Int
|
||||
when (ifElse.condition.operator) {
|
||||
when (condition.operator) {
|
||||
"==" -> {
|
||||
opcode = Opcode.BEQ
|
||||
firstReg = leftTr.resultReg
|
||||
@ -1032,21 +1093,23 @@ 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
|
||||
val branchDt: IRDataType
|
||||
val condition = ifElse.condition as PtBinaryExpression
|
||||
if(irDtLeft==IRDataType.FLOAT) {
|
||||
branchDt = IRDataType.BYTE
|
||||
compResultReg = registers.nextFree()
|
||||
val leftTr = expressionEval.translateExpression(ifElse.condition.left)
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, -1, leftTr.resultFpReg)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
val rightFpReg = registers.nextFreeFloat()
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = rightFpReg, fpValue = 0f)
|
||||
it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=compResultReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightFpReg)
|
||||
}
|
||||
elseBranch = when (ifElse.condition.operator) {
|
||||
elseBranch = when (condition.operator) {
|
||||
"==" -> Opcode.BNZ
|
||||
"!=" -> Opcode.BZ
|
||||
"<" -> Opcode.BGEZS
|
||||
@ -1058,10 +1121,10 @@ class IRCodeGen(
|
||||
} else {
|
||||
// integer comparisons
|
||||
branchDt = irDtLeft
|
||||
val tr = expressionEval.translateExpression(ifElse.condition.left)
|
||||
val tr = expressionEval.translateExpression(condition.left)
|
||||
compResultReg = tr.resultReg
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
elseBranch = when (ifElse.condition.operator) {
|
||||
elseBranch = when (condition.operator) {
|
||||
"==" -> Opcode.BNZ
|
||||
"!=" -> Opcode.BZ
|
||||
"<" -> if (signed) Opcode.BGEZS else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
|
||||
@ -1092,20 +1155,21 @@ 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
|
||||
val elseBranchSecondReg: Int
|
||||
val branchDt: IRDataType
|
||||
val condition = ifElse.condition as PtBinaryExpression
|
||||
if(irDtLeft==IRDataType.FLOAT) {
|
||||
val leftTr = expressionEval.translateExpression(ifElse.condition.left)
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, -1, leftTr.resultFpReg)
|
||||
val rightTr = expressionEval.translateExpression(ifElse.condition.right)
|
||||
val rightTr = expressionEval.translateExpression(condition.right)
|
||||
addToResult(result, rightTr, -1, rightTr.resultFpReg)
|
||||
val compResultReg = registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=compResultReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightTr.resultFpReg), null)
|
||||
val elseBranch = when (ifElse.condition.operator) {
|
||||
val elseBranch = when (condition.operator) {
|
||||
"==" -> Opcode.BNZ
|
||||
"!=" -> Opcode.BZ
|
||||
"<" -> Opcode.BGEZS
|
||||
@ -1133,11 +1197,11 @@ class IRCodeGen(
|
||||
} else {
|
||||
// integer comparisons
|
||||
branchDt = irDtLeft
|
||||
val leftTr = expressionEval.translateExpression(ifElse.condition.left)
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val rightTr = expressionEval.translateExpression(ifElse.condition.right)
|
||||
val rightTr = expressionEval.translateExpression(condition.right)
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
when (ifElse.condition.operator) {
|
||||
when (condition.operator) {
|
||||
"==" -> {
|
||||
elseBranchOpcode = Opcode.BNE
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
|
@ -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
|
||||
@ -17,6 +14,13 @@ class VmCodeGen: 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)
|
||||
}
|
||||
|
||||
|
||||
val irCodeGen = IRCodeGen(program, symbolTable, options, errors)
|
||||
val irProgram = irCodeGen.generate()
|
||||
return VmAssemblyProgram(irProgram.name, irProgram)
|
||||
|
@ -21,6 +21,8 @@ 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
|
||||
|
@ -997,6 +997,20 @@ _arg_s1 .word 0
|
||||
_arg_s2 .word 0
|
||||
.pend
|
||||
|
||||
strcmp_stack .proc
|
||||
; -- compare strings, both on stack.
|
||||
; Returns -1,0,1 in A, depeding on the ordering. Clobbers Y.
|
||||
inx
|
||||
lda P8ESTACK_LO,x
|
||||
ldy P8ESTACK_HI,x
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
inx
|
||||
lda P8ESTACK_LO,x
|
||||
ldy P8ESTACK_HI,x
|
||||
jmp strcmp_mem
|
||||
.pend
|
||||
|
||||
|
||||
strcmp_mem .proc
|
||||
; -- compares strings in s1 (AY) and s2 (P8ZP_SCRATCH_W2).
|
||||
|
@ -52,6 +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 moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999)
|
||||
|
||||
try {
|
||||
@ -126,6 +127,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
asmListfile == true,
|
||||
experimentalCodegen == true,
|
||||
varsHigh == true,
|
||||
useRPN == true,
|
||||
compilationTarget,
|
||||
evalStackAddr,
|
||||
processedSymbols,
|
||||
@ -190,6 +192,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
asmListfile == true,
|
||||
experimentalCodegen == true,
|
||||
varsHigh == true,
|
||||
useRPN == true,
|
||||
compilationTarget,
|
||||
evalStackAddr,
|
||||
processedSymbols,
|
||||
|
@ -36,6 +36,7 @@ class CompilerArguments(val filepath: Path,
|
||||
val asmListfile: Boolean,
|
||||
val experimentalCodegen: Boolean,
|
||||
val varsHigh: Boolean,
|
||||
val useRPN: Boolean,
|
||||
val compilationTarget: String,
|
||||
val evalStackBaseAddress: UInt?,
|
||||
val symbolDefs: Map<String, String>,
|
||||
@ -76,6 +77,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
asmListfile = args.asmListfile
|
||||
experimentalCodegen = args.experimentalCodegen
|
||||
varsHigh = args.varsHigh
|
||||
useRPN = args.useRPN
|
||||
evalStackBaseAddress = args.evalStackBaseAddress
|
||||
outputDir = args.outputDir.normalize()
|
||||
symbolDefs = args.symbolDefs
|
||||
@ -118,7 +120,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
// println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************")
|
||||
// printProgram(program)
|
||||
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||
// printAst(intermediateAst, ::println)
|
||||
// printAst(intermediateAst, true, ::println)
|
||||
|
||||
if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions)) {
|
||||
System.err.println("Error in codegeneration or assembler")
|
||||
|
@ -457,6 +457,8 @@ 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)
|
||||
|
@ -33,6 +33,7 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
varsHigh = false,
|
||||
useRPN = false,
|
||||
compilationTarget = target.name,
|
||||
evalStackBaseAddress = null,
|
||||
symbolDefs = emptyMap(),
|
||||
|
@ -50,6 +50,7 @@ class TestCompilerOptionSourcedirs: FunSpec({
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
varsHigh = false,
|
||||
useRPN = false,
|
||||
compilationTarget = Cx16Target.NAME,
|
||||
evalStackBaseAddress = null,
|
||||
symbolDefs = emptyMap(),
|
||||
|
@ -66,7 +66,7 @@ class TestIntermediateAst: FunSpec({
|
||||
val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall
|
||||
fcall.void shouldBe false
|
||||
fcall.type shouldBe DataType.UBYTE
|
||||
printAst(ast, ::println)
|
||||
printAst(ast, false, ::println)
|
||||
}
|
||||
|
||||
})
|
45
compiler/test/codegeneration/TestRPNCodeGen.kt
Normal file
45
compiler/test/codegeneration/TestRPNCodeGen.kt
Normal file
@ -0,0 +1,45 @@
|
||||
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
|
||||
}
|
||||
|
||||
})
|
@ -17,7 +17,8 @@ internal fun compileFile(
|
||||
outputDir: Path = prog8tests.helpers.outputDir,
|
||||
errors: IErrorReporter? = null,
|
||||
writeAssembly: Boolean = true,
|
||||
optFloatExpr: Boolean = true
|
||||
optFloatExpr: Boolean = true,
|
||||
useRPN: Boolean = false
|
||||
) : CompilationResult? {
|
||||
val filepath = fileDir.resolve(fileName)
|
||||
assumeReadableFile(filepath)
|
||||
@ -31,6 +32,7 @@ internal fun compileFile(
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
varsHigh = false,
|
||||
useRPN = useRPN,
|
||||
platform.name,
|
||||
evalStackBaseAddress = null,
|
||||
symbolDefs = emptyMap(),
|
||||
@ -51,11 +53,12 @@ internal fun compileText(
|
||||
sourceText: String,
|
||||
errors: IErrorReporter? = null,
|
||||
writeAssembly: Boolean = true,
|
||||
optFloatExpr: Boolean = true
|
||||
optFloatExpr: Boolean = true,
|
||||
useRPN: 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)
|
||||
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, useRPN=useRPN)
|
||||
}
|
||||
|
@ -1,5 +1,19 @@
|
||||
TODO
|
||||
====
|
||||
RPN: examples/line-circle-txt crashes
|
||||
RPN: examples/turtlegfx crashes
|
||||
RPN: examples/maze crashes
|
||||
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
|
||||
|
||||
RPN: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt
|
||||
RPN: check BinExprSplitter disablement any effect for RPN?
|
||||
RPN: Implement RPN codegen for IR.
|
||||
|
||||
- Move asmExtra vars into BSS as well, now are .byte 0 allocated
|
||||
|
||||
|
||||
For next minor release
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -43,7 +43,7 @@ main {
|
||||
DX[lp] = true
|
||||
else
|
||||
BX[lp]=BX[lp]-1
|
||||
} else if DX[lp] {
|
||||
} else {
|
||||
if (BX[lp] == txt.DEFAULT_WIDTH-1) {
|
||||
BX[lp] = txt.DEFAULT_WIDTH-2
|
||||
DX[lp] = false
|
||||
@ -56,7 +56,7 @@ main {
|
||||
DY[lp] = true
|
||||
else
|
||||
BY[lp]=BY[lp]-1
|
||||
} else if DY[lp] == 1 {
|
||||
} else {
|
||||
if (BY[lp] == txt.DEFAULT_HEIGHT-1) {
|
||||
BY[lp] = txt.DEFAULT_HEIGHT-2
|
||||
DY[lp] = false
|
||||
|
@ -1,11 +1,21 @@
|
||||
%import math
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
; Note: this program is compatible with C64 and CX16.
|
||||
|
||||
main {
|
||||
uword[10] answers_animals
|
||||
|
||||
sub start() {
|
||||
ubyte current_question = 1
|
||||
uword previous_animals = 33
|
||||
current_question = msb(answers_animals[current_question]) ; TODO takes 1 more vm registers than 8.10
|
||||
answers_animals[current_question] = mkword(msb(previous_animals), 0) ; TODO takes 1 more vm registers than 8.10
|
||||
; TODO expected result: 7 registers in 8.10, now takes 9 instead
|
||||
bool x
|
||||
ubyte y
|
||||
repeat 20 {
|
||||
x = math.rnd() & 1
|
||||
y = ((math.rnd()&1)!=0)
|
||||
txt.print_ub(x)
|
||||
txt.spc()
|
||||
txt.print_ub(y)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,8 @@ class RequestParser : Take {
|
||||
quietAssembler = false,
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
varsHigh = false
|
||||
varsHigh = false,
|
||||
useRPN = false
|
||||
)
|
||||
val compilationResult = compileProgram(args)
|
||||
return RsJson(Jsonding())
|
||||
|
Loading…
x
Reference in New Issue
Block a user