mirror of
https://github.com/irmen/prog8.git
synced 2025-02-18 05:30:34 +00:00
more Rpn optimizations
This commit is contained in:
parent
52b560e72d
commit
6e4ae034b2
@ -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)
|
* 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>()
|
val result = mutableMapOf<String, StNode>()
|
||||||
fun collect(node: StNode) {
|
fun collect(node: StNode) {
|
||||||
for(child in node.children) {
|
for(child in node.children) {
|
||||||
@ -24,9 +29,14 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
collect(this)
|
collect(this)
|
||||||
result
|
cachedFlat = result
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fun resetCachedFlat() {
|
||||||
|
// cachedFlat = null
|
||||||
|
// }
|
||||||
|
|
||||||
val allVariables: Collection<StStaticVariable> by lazy {
|
val allVariables: Collection<StStaticVariable> by lazy {
|
||||||
val vars = mutableListOf<StStaticVariable>()
|
val vars = mutableListOf<StStaticVariable>()
|
||||||
fun collect(node: StNode) {
|
fun collect(node: StNode) {
|
||||||
|
@ -472,8 +472,8 @@ class AsmGen6502Internal (
|
|||||||
internal fun restoreXafterCall(functionCall: PtFunctionCall) =
|
internal fun restoreXafterCall(functionCall: PtFunctionCall) =
|
||||||
functioncallAsmGen.restoreXafterCall(functionCall)
|
functioncallAsmGen.restoreXafterCall(functionCall)
|
||||||
|
|
||||||
internal fun translateNormalAssignment(assign: AsmAssignment) =
|
internal fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) =
|
||||||
assignmentAsmGen.translateNormalAssignment(assign)
|
assignmentAsmGen.translateNormalAssignment(assign, scope)
|
||||||
|
|
||||||
internal fun assignExpressionToRegister(expr: PtExpression, register: RegisterOrPair, signed: Boolean=false) =
|
internal fun assignExpressionToRegister(expr: PtExpression, register: RegisterOrPair, signed: Boolean=false) =
|
||||||
assignmentAsmGen.assignExpressionToRegister(expr, register, signed)
|
assignmentAsmGen.assignExpressionToRegister(expr, register, signed)
|
||||||
@ -481,8 +481,8 @@ class AsmGen6502Internal (
|
|||||||
internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType, scope: IPtSubroutine?) =
|
internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType, scope: IPtSubroutine?) =
|
||||||
assignmentAsmGen.assignExpressionToVariable(expr, asmVarName, dt, scope)
|
assignmentAsmGen.assignExpressionToVariable(expr, asmVarName, dt, scope)
|
||||||
|
|
||||||
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, pos: Position, signed: Boolean=false) =
|
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, scope: IPtSubroutine?, pos: Position, signed: Boolean=false) =
|
||||||
assignmentAsmGen.assignVariableToRegister(asmVarName, register, signed, pos)
|
assignmentAsmGen.assignVariableToRegister(asmVarName, register, signed, scope, pos)
|
||||||
|
|
||||||
internal fun assignRegister(reg: RegisterOrPair, target: AsmAssignTarget) {
|
internal fun assignRegister(reg: RegisterOrPair, target: AsmAssignTarget) {
|
||||||
when(reg) {
|
when(reg) {
|
||||||
@ -512,7 +512,7 @@ class AsmGen6502Internal (
|
|||||||
AsmAssignment(
|
AsmAssignment(
|
||||||
AsmAssignSource(SourceStorageKind.REGISTER, program, this, target.datatype, register=RegisterOrPair.AY),
|
AsmAssignSource(SourceStorageKind.REGISTER, program, this, target.datatype, register=RegisterOrPair.AY),
|
||||||
target, program.memsizer, value.position
|
target, program.memsizer, value.position
|
||||||
)
|
), value.definingISub()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
@ -626,11 +626,11 @@ class AsmGen6502Internal (
|
|||||||
val name = asmVariableName(stmt.count as PtIdentifier)
|
val name = asmVariableName(stmt.count as PtIdentifier)
|
||||||
when(vardecl.type) {
|
when(vardecl.type) {
|
||||||
DataType.UBYTE, DataType.BYTE -> {
|
DataType.UBYTE, DataType.BYTE -> {
|
||||||
assignVariableToRegister(name, RegisterOrPair.Y, stmt.count.position)
|
assignVariableToRegister(name, RegisterOrPair.Y, stmt.definingISub(), stmt.count.position)
|
||||||
repeatCountInY(stmt, endLabel)
|
repeatCountInY(stmt, endLabel)
|
||||||
}
|
}
|
||||||
DataType.UWORD, DataType.WORD -> {
|
DataType.UWORD, DataType.WORD -> {
|
||||||
assignVariableToRegister(name, RegisterOrPair.AY, stmt.count.position)
|
assignVariableToRegister(name, RegisterOrPair.AY, stmt.definingISub(), stmt.count.position)
|
||||||
repeatWordCountInAY(endLabel, stmt)
|
repeatWordCountInAY(endLabel, stmt)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid loop variable datatype $vardecl")
|
else -> throw AssemblyError("invalid loop variable datatype $vardecl")
|
||||||
@ -1062,7 +1062,9 @@ $repeatLabel lda $counterVar
|
|||||||
// could be that the index was a constant numeric byte but converted to word, check that
|
// could be that the index was a constant numeric byte but converted to word, check that
|
||||||
val constIdx = right as? PtNumber
|
val constIdx = right as? PtNumber
|
||||||
if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) {
|
if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) {
|
||||||
return Pair(left, PtNumber(DataType.UBYTE, constIdx.number, constIdx.position))
|
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
|
// could be that the index was typecasted into uword, check that
|
||||||
val rightTc = right as? PtTypeCast
|
val rightTc = right as? PtTypeCast
|
||||||
@ -1160,26 +1162,61 @@ $repeatLabel lda $counterVar
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun findSubroutineParameter(name: String, asmgen: AsmGen6502Internal): PtSubroutineParameter? {
|
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)
|
if(node is PtSubroutineParameter)
|
||||||
return node
|
return node
|
||||||
return node.definingSub()?.parameters?.singleOrNull { it.name===name }
|
return node.definingSub()?.parameters?.singleOrNull { it.name===name }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateCompareAndJumpIfTrueRPN(expr: PtRpn, jump: PtJump) {
|
private fun translateCompareAndJumpIfTrueRPN(expr: PtRpn, jump: PtJump) {
|
||||||
|
val (left, oper, right) = expr.finalOperation()
|
||||||
|
if(expr.children.size>3) {
|
||||||
|
TODO("RPN comparison too complex ${expr.position}")
|
||||||
|
}
|
||||||
|
|
||||||
|
require(left is PtExpression && right is PtExpression)
|
||||||
|
|
||||||
|
if(oper.operator !in ComparisonOperators)
|
||||||
|
throw AssemblyError("must be comparison expression")
|
||||||
|
|
||||||
|
// 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 rightConstVal = right as? PtNumber
|
||||||
|
|
||||||
val label = when {
|
val label = when {
|
||||||
jump.generatedLabel!=null -> jump.generatedLabel!!
|
jump.generatedLabel!=null -> jump.generatedLabel!!
|
||||||
jump.identifier!=null -> asmSymbolName(jump.identifier!!)
|
jump.identifier!=null -> asmSymbolName(jump.identifier!!)
|
||||||
jump.address!=null -> jump.address!!.toHex()
|
jump.address!=null -> jump.address!!.toHex()
|
||||||
else -> throw AssemblyError("weird jump")
|
else -> throw AssemblyError("weird jump")
|
||||||
}
|
}
|
||||||
assignExpressionToRegister(expr, RegisterOrPair.A)
|
if (rightConstVal!=null && rightConstVal.number == 0.0)
|
||||||
out(" bne $label")
|
testZeroAndJump(left, invertedComparisonOperator, label)
|
||||||
|
else {
|
||||||
|
val leftConstVal = left as? PtNumber
|
||||||
|
testNonzeroComparisonAndJump(left, invertedComparisonOperator, right, label, leftConstVal, rightConstVal)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateCompareAndJumpIfFalseRPN(expr: PtRpn, jumpIfFalseLabel: String) {
|
private fun translateCompareAndJumpIfFalseRPN(expr: PtRpn, jumpIfFalseLabel: String) {
|
||||||
assignExpressionToRegister(expr, RegisterOrPair.A)
|
val (left, oper, right) = expr.finalOperation()
|
||||||
out(" beq $jumpIfFalseLabel")
|
if(expr.children.size>3) {
|
||||||
|
TODO("RPN comparison too complex ${expr.position}")
|
||||||
|
}
|
||||||
|
|
||||||
|
require(left is PtExpression && 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) {
|
private fun translateCompareAndJumpIfTrue(expr: PtBinaryExpression, jump: PtJump) {
|
||||||
@ -1374,7 +1411,7 @@ $repeatLabel lda $counterVar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun testNonzeroComparisonAndJump(
|
internal fun testNonzeroComparisonAndJump(
|
||||||
left: PtExpression,
|
left: PtExpression,
|
||||||
operator: String,
|
operator: String,
|
||||||
right: PtExpression,
|
right: PtExpression,
|
||||||
|
@ -250,7 +250,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
|||||||
else
|
else
|
||||||
AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen)
|
AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen)
|
||||||
val assign = AsmAssignment(src, target, program.memsizer, fcall.position)
|
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?) {
|
private fun funcSqrt16(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||||
@ -998,7 +998,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, conv.dt, null, value.position, variableAsmName = varname)
|
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, conv.dt, null, value.position, variableAsmName = varname)
|
||||||
val assign = AsmAssignment(src, tgt, program.memsizer, value.position)
|
val assign = AsmAssignment(src, tgt, program.memsizer, value.position)
|
||||||
asmgen.translateNormalAssignment(assign)
|
asmgen.translateNormalAssignment(assign, scope)
|
||||||
}
|
}
|
||||||
conv.reg != null -> {
|
conv.reg != null -> {
|
||||||
val src = when (conv.dt) {
|
val src = when (conv.dt) {
|
||||||
@ -1016,7 +1016,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
val tgt = AsmAssignTarget.fromRegisters(conv.reg!!, false, value.position, null, asmgen)
|
val tgt = AsmAssignTarget.fromRegisters(conv.reg!!, false, value.position, null, asmgen)
|
||||||
val assign = AsmAssignment(src, tgt, program.memsizer, value.position)
|
val assign = AsmAssignment(src, tgt, program.memsizer, value.position)
|
||||||
asmgen.translateNormalAssignment(assign)
|
asmgen.translateNormalAssignment(assign, scope)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("callconv")
|
else -> throw AssemblyError("callconv")
|
||||||
}
|
}
|
||||||
|
@ -478,15 +478,15 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
|||||||
asmgen.out(" lda #0 | sta P8ESTACK_LO+1,x | sta P8ESTACK_HI+1,x")
|
asmgen.out(" lda #0 | sta P8ESTACK_LO+1,x | sta P8ESTACK_HI+1,x")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
var left = amount
|
var amountLeft = amount
|
||||||
while (left >= 7) {
|
while (amountLeft >= 7) {
|
||||||
asmgen.out(" jsr math.shift_right_uw_7")
|
asmgen.out(" jsr math.shift_right_uw_7")
|
||||||
left -= 7
|
amountLeft -= 7
|
||||||
}
|
}
|
||||||
if (left in 0..2)
|
if (amountLeft in 0..2)
|
||||||
repeat(left) { asmgen.out(" lsr P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
repeat(amountLeft) { asmgen.out(" lsr P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
||||||
else
|
else
|
||||||
asmgen.out(" jsr math.shift_right_uw_$left")
|
asmgen.out(" jsr math.shift_right_uw_$amountLeft")
|
||||||
}
|
}
|
||||||
DataType.WORD -> {
|
DataType.WORD -> {
|
||||||
if(amount>=16) {
|
if(amount>=16) {
|
||||||
@ -503,15 +503,15 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
|||||||
+""")
|
+""")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
var left = amount
|
var amountLeft = amount
|
||||||
while (left >= 7) {
|
while (amountLeft >= 7) {
|
||||||
asmgen.out(" jsr math.shift_right_w_7")
|
asmgen.out(" jsr math.shift_right_w_7")
|
||||||
left -= 7
|
amountLeft -= 7
|
||||||
}
|
}
|
||||||
if (left in 0..2)
|
if (amountLeft in 0..2)
|
||||||
repeat(left) { asmgen.out(" lda P8ESTACK_HI+1,x | asl a | ror P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
repeat(amountLeft) { asmgen.out(" lda P8ESTACK_HI+1,x | asl a | ror P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") }
|
||||||
else
|
else
|
||||||
asmgen.out(" jsr math.shift_right_w_$left")
|
asmgen.out(" jsr math.shift_right_w_$amountLeft")
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("weird type")
|
else -> throw AssemblyError("weird type")
|
||||||
}
|
}
|
||||||
@ -531,15 +531,15 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
|
|||||||
asmgen.out(" sta P8ESTACK_LO+1,x")
|
asmgen.out(" sta P8ESTACK_LO+1,x")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var left = amount
|
var amountLeft = amount
|
||||||
while (left >= 7) {
|
while (amountLeft >= 7) {
|
||||||
asmgen.out(" jsr math.shift_left_w_7")
|
asmgen.out(" jsr math.shift_left_w_7")
|
||||||
left -= 7
|
amountLeft -= 7
|
||||||
}
|
}
|
||||||
if (left in 0..2)
|
if (amountLeft in 0..2)
|
||||||
repeat(left) { asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") }
|
repeat(amountLeft) { asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") }
|
||||||
else
|
else
|
||||||
asmgen.out(" jsr math.shift_left_w_$left")
|
asmgen.out(" jsr math.shift_left_w_$amountLeft")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
|||||||
// we need to sign extend the source, do this via temporary word variable
|
// 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, sub)
|
||||||
asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", value.type)
|
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 {
|
} else {
|
||||||
val target: AsmAssignTarget =
|
val target: AsmAssignTarget =
|
||||||
if(parameter.value.type in ByteDatatypes && (register==RegisterOrPair.AX || register == RegisterOrPair.AY || register==RegisterOrPair.XY || register in Cx16VirtualRegisters))
|
if(parameter.value.type in ByteDatatypes && (register==RegisterOrPair.AX || register == RegisterOrPair.AY || register==RegisterOrPair.XY || register in Cx16VirtualRegisters))
|
||||||
@ -221,7 +221,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
|||||||
} else {
|
} else {
|
||||||
AsmAssignSource.fromAstSource(value, program, asmgen).adjustSignedUnsigned(target)
|
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), sub)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,36 @@
|
|||||||
package prog8.codegen.cpu6502.assignment
|
package prog8.codegen.cpu6502.assignment
|
||||||
|
|
||||||
|
import prog8.code.StStaticVariable
|
||||||
import prog8.code.SymbolTable
|
import prog8.code.SymbolTable
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.codegen.cpu6502.AsmGen6502Internal
|
import prog8.codegen.cpu6502.AsmGen6502Internal
|
||||||
import prog8.codegen.cpu6502.VariableAllocator
|
import prog8.codegen.cpu6502.VariableAllocator
|
||||||
import prog8.codegen.cpu6502.returnsWhatWhere
|
import prog8.codegen.cpu6502.returnsWhatWhere
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
internal class AssignmentAsmGen(private val program: PtProgram,
|
internal class AssignmentAsmGen(private val program: PtProgram,
|
||||||
symbolTable: SymbolTable,
|
private val symbolTable: SymbolTable,
|
||||||
private val asmgen: AsmGen6502Internal,
|
private val asmgen: AsmGen6502Internal,
|
||||||
private val allocator: VariableAllocator) {
|
private val allocator: VariableAllocator) {
|
||||||
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator)
|
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator)
|
||||||
private val rpnAssignmentAsmGen = RpnExpressionAsmGen(program, symbolTable, asmgen)
|
|
||||||
|
|
||||||
fun translate(assignment: PtAssignment) {
|
fun translate(assignment: PtAssignment) {
|
||||||
val target = AsmAssignTarget.fromAstAssignment(assignment.target, assignment.definingISub(), asmgen)
|
val target = AsmAssignTarget.fromAstAssignment(assignment.target, assignment.definingISub(), asmgen)
|
||||||
val source = AsmAssignSource.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target)
|
val source = AsmAssignSource.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target)
|
||||||
val assign = AsmAssignment(source, target, program.memsizer, assignment.position)
|
val assign = AsmAssignment(source, target, program.memsizer, assignment.position)
|
||||||
translateNormalAssignment(assign)
|
translateNormalAssignment(assign, assignment.definingISub())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun translate(augmentedAssign: PtAugmentedAssign) {
|
fun translate(augmentedAssign: PtAugmentedAssign) {
|
||||||
val target = AsmAssignTarget.fromAstAssignment(augmentedAssign.target, augmentedAssign.definingISub(), asmgen)
|
val target = AsmAssignTarget.fromAstAssignment(augmentedAssign.target, augmentedAssign.definingISub(), asmgen)
|
||||||
val source = AsmAssignSource.fromAstSource(augmentedAssign.value, program, asmgen).adjustSignedUnsigned(target)
|
val source = AsmAssignSource.fromAstSource(augmentedAssign.value, program, asmgen).adjustSignedUnsigned(target)
|
||||||
val assign = AsmAugmentedAssignment(source, augmentedAssign.operator, target, program.memsizer, augmentedAssign.position)
|
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) {
|
when(assign.source.kind) {
|
||||||
SourceStorageKind.LITERALNUMBER -> {
|
SourceStorageKind.LITERALNUMBER -> {
|
||||||
// simple case: assign a constant number
|
// simple case: assign a constant number
|
||||||
@ -164,7 +165,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SourceStorageKind.EXPRESSION -> {
|
SourceStorageKind.EXPRESSION -> {
|
||||||
assignExpression(assign)
|
assignExpression(assign, scope)
|
||||||
}
|
}
|
||||||
SourceStorageKind.REGISTER -> {
|
SourceStorageKind.REGISTER -> {
|
||||||
asmgen.assignRegister(assign.source.register!!, assign.target)
|
asmgen.assignRegister(assign.source.register!!, assign.target)
|
||||||
@ -176,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!!) {
|
when(val value = assign.source.expression!!) {
|
||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
val sourceName = asmgen.asmSymbolName(value.identifier)
|
val sourceName = asmgen.asmSymbolName(value.identifier)
|
||||||
@ -289,17 +290,17 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
AsmAssignment(
|
AsmAssignment(
|
||||||
AsmAssignSource.fromAstSource(value.value, program, asmgen),
|
AsmAssignSource.fromAstSource(value.value, program, asmgen),
|
||||||
assign.target, program.memsizer, assign.position
|
assign.target, program.memsizer, assign.position
|
||||||
)
|
), scope
|
||||||
)
|
)
|
||||||
when (value.operator) {
|
when (value.operator) {
|
||||||
"+" -> {}
|
"+" -> {}
|
||||||
"-" -> inplaceNegate(assign, true)
|
"-" -> inplaceNegate(assign, true, scope)
|
||||||
"~" -> inplaceInvert(assign)
|
"~" -> inplaceInvert(assign, scope)
|
||||||
"not" -> throw AssemblyError("not should have been replaced in the Ast by ==0")
|
"not" -> throw AssemblyError("not should have been replaced in the Ast by ==0")
|
||||||
else -> throw AssemblyError("invalid prefix operator")
|
else -> throw AssemblyError("invalid prefix operator")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assignPrefixedExpressionToArrayElt(assign)
|
assignPrefixedExpressionToArrayElt(assign, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtContainmentCheck -> {
|
is PtContainmentCheck -> {
|
||||||
@ -316,7 +317,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtRpn -> {
|
is PtRpn -> {
|
||||||
if(!rpnAssignmentAsmGen.attemptAssignOptimizedExpr(assign)) {
|
if(!attemptAssignOptimizedExprRPN(assign, scope!!)) {
|
||||||
// All remaining binary expressions just evaluate via the stack for now.
|
// 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
|
// 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,
|
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,
|
||||||
@ -328,7 +329,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assignPrefixedExpressionToArrayElt(assign: AsmAssignment) {
|
private fun assignPrefixedExpressionToArrayElt(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||||
require(assign.source.expression is PtPrefix)
|
require(assign.source.expression is PtPrefix)
|
||||||
if(assign.source.datatype==DataType.FLOAT) {
|
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.
|
// floatarray[x] = -value ... just use FAC1 to calculate the expression into and then store that back into the array.
|
||||||
@ -340,7 +341,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
val assignToTempvar = AsmAssignment(assign.source,
|
val assignToTempvar = AsmAssignment(assign.source,
|
||||||
AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, assign.target.datatype, assign.target.scope, assign.target.position,
|
AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, assign.target.datatype, assign.target.scope, assign.target.position,
|
||||||
variableAsmName=tempvar, origAstTarget = assign.target.origAstTarget), program.memsizer, assign.position)
|
variableAsmName=tempvar, origAstTarget = assign.target.origAstTarget), program.memsizer, assign.position)
|
||||||
asmgen.translateNormalAssignment(assignToTempvar)
|
asmgen.translateNormalAssignment(assignToTempvar, scope)
|
||||||
when(assign.target.datatype) {
|
when(assign.target.datatype) {
|
||||||
in ByteDatatypes -> assignVariableByte(assign.target, tempvar)
|
in ByteDatatypes -> assignVariableByte(assign.target, tempvar)
|
||||||
in WordDatatypes -> assignVariableWord(assign.target, tempvar)
|
in WordDatatypes -> assignVariableWord(assign.target, tempvar)
|
||||||
@ -361,6 +362,221 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
fun simpleLogicalBytesExpr() {
|
||||||
|
// both left and right expression operands are simple.
|
||||||
|
require(left is PtExpression && right is PtExpression)
|
||||||
|
if (right is PtNumber || right is PtIdentifier)
|
||||||
|
assignLogicalWithSimpleRightOperandByte(assign.target, left, oper.operator, right)
|
||||||
|
else if (left is PtNumber || left is PtIdentifier)
|
||||||
|
assignLogicalWithSimpleRightOperandByte(assign.target, right, oper.operator, left)
|
||||||
|
else {
|
||||||
|
assignExpressionToRegister(left, RegisterOrPair.A, false)
|
||||||
|
asmgen.saveRegisterStack(CpuRegister.A, false)
|
||||||
|
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, scope)
|
||||||
|
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||||
|
when (oper.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(assign.target, CpuRegister.A)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun simpleLogicalWordsExpr() {
|
||||||
|
// both left and right expression operands are simple.
|
||||||
|
require(left is PtExpression && right is PtExpression)
|
||||||
|
if (right is PtNumber || right is PtIdentifier)
|
||||||
|
assignLogicalWithSimpleRightOperandWord(assign.target, left, oper.operator, right)
|
||||||
|
else if (left is PtNumber || left is PtIdentifier)
|
||||||
|
assignLogicalWithSimpleRightOperandWord(assign.target, right, oper.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, scope)
|
||||||
|
when (oper.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(assign.target, RegisterOrPair.AY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value.children.size==3 && oper.operator in setOf("&", "|", "^", "and", "or", "xor")) {
|
||||||
|
if(left is PtExpression && right is PtExpression) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(dt, name, null))
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var depth=0
|
||||||
|
value.children.forEach {
|
||||||
|
when (it) {
|
||||||
|
is PtRpnOperator -> {
|
||||||
|
val varDt = getVarDt(it.type)
|
||||||
|
val rightvar = evalVars.getValue(varDt).pop()
|
||||||
|
val leftvar = evalVars.getValue(varDt).pop()
|
||||||
|
depth-=2
|
||||||
|
val resultVarname = evalVarName(it.type, depth)
|
||||||
|
depth++
|
||||||
|
require(resultVarname==leftvar)
|
||||||
|
// TODO no longer needed? symbolTable.resetCachedFlat()
|
||||||
|
if(it.operator in ComparisonOperators) {
|
||||||
|
val scopeName = (scope as PtNamedNode).scopedName
|
||||||
|
val comparison = PtRpn(DataType.UBYTE, assign.position)
|
||||||
|
comparison.addRpnNode(PtIdentifier("$scopeName.$resultVarname", it.type, value.position))
|
||||||
|
comparison.addRpnNode(PtIdentifier("$scopeName.$rightvar", it.type, 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 {
|
||||||
|
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, DataType.UBYTE, variableAsmName = rightvar)
|
||||||
|
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, 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, scope)
|
||||||
|
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 assignRPNComparison(assign: AsmAssignment, comparison: PtRpn) {
|
||||||
|
val (left, 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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(comparison.children.size>3) {
|
||||||
|
TODO("RPN comparison too complex ${comparison.position}")
|
||||||
|
}
|
||||||
|
|
||||||
|
require(left is PtExpression)
|
||||||
|
val leftNum = left as? PtNumber
|
||||||
|
val rightNum = right as? PtNumber
|
||||||
|
val jumpIfFalseLabel = asmgen.makeLabel("cmp")
|
||||||
|
|
||||||
|
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)
|
||||||
|
asmgen.out("; cmp done")
|
||||||
|
}
|
||||||
|
|
||||||
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||||
if(expr.operator in ComparisonOperators) {
|
if(expr.operator in ComparisonOperators) {
|
||||||
if(expr.right.asConstInteger() == 0) {
|
if(expr.right.asConstInteger() == 0) {
|
||||||
@ -743,6 +959,80 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun attemptAssignToByteCompareZeroRPN(expr: PtRpn, assign: AsmAssignment): Boolean {
|
||||||
|
val (left, oper, right) = expr.finalOperation()
|
||||||
|
if(expr.children.size!=3 || left !is PtExpression)
|
||||||
|
return false
|
||||||
|
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 {
|
private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||||
when (expr.operator) {
|
when (expr.operator) {
|
||||||
"==" -> {
|
"==" -> {
|
||||||
@ -1030,7 +1320,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
// have to typecast the float number on the fly down to an integer
|
// have to typecast the float number on the fly down to an integer
|
||||||
assignExpressionToRegister(value, RegisterOrPair.FAC1, target.datatype in SignedDatatypes)
|
assignExpressionToRegister(value, RegisterOrPair.FAC1, target.datatype in SignedDatatypes)
|
||||||
assignTypeCastedFloatFAC1("P8ZP_SCRATCH_W1", target.datatype)
|
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
|
return
|
||||||
} else {
|
} else {
|
||||||
if(!(valueDt isAssignableTo targetDt)) {
|
if(!(valueDt isAssignableTo targetDt)) {
|
||||||
@ -1135,7 +1425,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
lsb.add(value)
|
lsb.add(value)
|
||||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb)
|
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb)
|
||||||
val assign = AsmAssignment(src, target, program.memsizer, value.position)
|
val assign = AsmAssignment(src, target, program.memsizer, value.position)
|
||||||
translateNormalAssignment(assign)
|
translateNormalAssignment(assign, value.definingISub())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assignTypeCastedFloatFAC1(targetAsmVarName: String, targetDt: DataType) {
|
private fun assignTypeCastedFloatFAC1(targetAsmVarName: String, targetDt: DataType) {
|
||||||
@ -2869,7 +3159,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
|
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
|
||||||
val tgt = AsmAssignTarget.fromRegisters(register, signed, expr.position, null, asmgen)
|
val tgt = AsmAssignTarget.fromRegisters(register, signed, expr.position, null, asmgen)
|
||||||
val assign = AsmAssignment(src, tgt, program.memsizer, expr.position)
|
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, scope: IPtSubroutine?) {
|
||||||
@ -2879,18 +3169,18 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
|
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, scope, expr.position, variableAsmName = asmVarName)
|
||||||
val assign = AsmAssignment(src, tgt, program.memsizer, expr.position)
|
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 tgt = AsmAssignTarget.fromRegisters(register, signed, pos, null, asmgen)
|
||||||
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, tgt.datatype, variableAsmName = asmVarName)
|
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, tgt.datatype, variableAsmName = asmVarName)
|
||||||
val assign = AsmAssignment(src, tgt, program.memsizer, Position.DUMMY)
|
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
|
val target = assign.target
|
||||||
when (assign.target.datatype) {
|
when (assign.target.datatype) {
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
@ -2935,7 +3225,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TargetStorageKind.STACK -> TODO("no asm gen for byte stack invert")
|
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")
|
else -> throw AssemblyError("weird target")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2960,7 +3250,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TargetStorageKind.STACK -> TODO("no asm gen for word stack invert")
|
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")
|
else -> throw AssemblyError("weird target")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2968,7 +3258,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 target = assign.target
|
||||||
val datatype = if(ignoreDatatype) {
|
val datatype = if(ignoreDatatype) {
|
||||||
when(target.datatype) {
|
when(target.datatype) {
|
||||||
@ -3003,7 +3293,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that")
|
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that")
|
||||||
TargetStorageKind.STACK -> TODO("no asm gen for byte stack negate")
|
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")
|
else -> throw AssemblyError("weird target")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3063,7 +3353,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that")
|
TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that")
|
||||||
TargetStorageKind.STACK -> TODO("no asm gen for word stack negate")
|
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")
|
else -> throw AssemblyError("weird target")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3085,7 +3375,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
TargetStorageKind.STACK -> TODO("no asm gen for float stack negate")
|
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")
|
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 asmgen: AsmGen6502Internal,
|
||||||
private val allocator: VariableAllocator
|
private val allocator: VariableAllocator
|
||||||
) {
|
) {
|
||||||
fun translate(assign: AsmAugmentedAssignment) {
|
fun translate(assign: AsmAugmentedAssignment, scope: IPtSubroutine?) {
|
||||||
|
|
||||||
when(assign.operator) {
|
when(assign.operator) {
|
||||||
"-" -> {
|
"-" -> {
|
||||||
val a2 = AsmAssignment(assign.source, assign.target, assign.memsizer, assign.position)
|
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)
|
val a2 = AsmAssignment(assign.source, assign.target, assign.memsizer, assign.position)
|
||||||
assignmentAsmGen.inplaceInvert(a2)
|
assignmentAsmGen.inplaceInvert(a2, scope)
|
||||||
}
|
}
|
||||||
"+" -> { /* is a nop */ }
|
"+" -> { /* is a nop */ }
|
||||||
else -> {
|
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)
|
||||||
">>=" -> inplaceModification(assign.target, ">>", srcValue)
|
">>=" -> inplaceModification(assign.target, ">>", srcValue)
|
||||||
|
"%=" -> inplaceModification(assign.target, "%", srcValue)
|
||||||
else -> throw AssemblyError("invalid augmented assign operator ${assign.operator}")
|
else -> throw AssemblyError("invalid augmented assign operator ${assign.operator}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package prog8.codegen.cpu6502.assignment
|
|
||||||
|
|
||||||
import prog8.code.SymbolTable
|
|
||||||
import prog8.code.ast.PtProgram
|
|
||||||
import prog8.code.ast.PtRpn
|
|
||||||
import prog8.codegen.cpu6502.AsmGen6502Internal
|
|
||||||
|
|
||||||
internal class RpnExpressionAsmGen(
|
|
||||||
val program: PtProgram,
|
|
||||||
val symbolTable: SymbolTable,
|
|
||||||
val asmgen: AsmGen6502Internal
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun attemptAssignOptimizedExpr(assign: AsmAssignment): Boolean {
|
|
||||||
val value = assign.source.expression as PtRpn
|
|
||||||
println("TODO: RPN: optimized assignment ${value.position} maxdepth=${value.maxDepth()}") // TODO RPN: optimized assignment
|
|
||||||
// NOTE: don't forgot to evaluate the rest of the RPN expr as well
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -898,6 +898,7 @@ class IRCodeGen(
|
|||||||
|
|
||||||
private fun translate(ifElse: PtIfElse): IRCodeChunks {
|
private fun translate(ifElse: PtIfElse): IRCodeChunks {
|
||||||
val condition = ifElse.condition
|
val condition = ifElse.condition
|
||||||
|
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
|
||||||
when (condition) {
|
when (condition) {
|
||||||
is PtBinaryExpression -> {
|
is PtBinaryExpression -> {
|
||||||
if(condition.operator !in ComparisonOperators)
|
if(condition.operator !in ComparisonOperators)
|
||||||
@ -905,7 +906,6 @@ class IRCodeGen(
|
|||||||
|
|
||||||
val signed = condition.left.type in SignedDatatypes
|
val signed = condition.left.type in SignedDatatypes
|
||||||
val irDtLeft = irType(condition.left.type)
|
val irDtLeft = irType(condition.left.type)
|
||||||
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
|
|
||||||
return when {
|
return when {
|
||||||
goto!=null && ifElse.elseScope.children.isEmpty() -> translateIfFollowedByJustGoto(ifElse, goto, irDtLeft, signed)
|
goto!=null && ifElse.elseScope.children.isEmpty() -> translateIfFollowedByJustGoto(ifElse, goto, irDtLeft, signed)
|
||||||
constValue(condition.right) == 0.0 -> translateIfElseZeroComparison(ifElse, irDtLeft, signed)
|
constValue(condition.right) == 0.0 -> translateIfElseZeroComparison(ifElse, irDtLeft, signed)
|
||||||
@ -913,52 +913,92 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtRpn -> {
|
is PtRpn -> {
|
||||||
TODO("RPN ifelse (intermediate codegen) $condition")
|
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 -> {
|
else -> {
|
||||||
TODO("weird condition node: $condition")
|
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> {
|
private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump, irDtLeft: IRDataType, signed: Boolean): MutableList<IRCodeChunkBase> {
|
||||||
if(program.binaryExpressionsAreRPN) {
|
require(!program.binaryExpressionsAreRPN)
|
||||||
TODO ("RPN (intermediate codegen)")
|
val condition = ifElse.condition as PtBinaryExpression
|
||||||
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
if (irDtLeft == IRDataType.FLOAT) {
|
||||||
|
val leftTr = expressionEval.translateExpression(condition.left)
|
||||||
|
addToResult(result, leftTr, -1, leftTr.resultFpReg)
|
||||||
|
val rightTr = expressionEval.translateExpression(condition.right)
|
||||||
|
addToResult(result, rightTr, -1, rightTr.resultFpReg)
|
||||||
|
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 (condition.operator) {
|
||||||
|
"==" -> Opcode.BZ
|
||||||
|
"!=" -> Opcode.BNZ
|
||||||
|
"<" -> Opcode.BLEZS
|
||||||
|
">" -> Opcode.BGEZS
|
||||||
|
"<=" -> Opcode.BLZS
|
||||||
|
">=" -> Opcode.BGZS
|
||||||
|
else -> throw AssemblyError("weird operator")
|
||||||
|
}
|
||||||
|
it += if (goto.address != null)
|
||||||
|
IRInstruction(
|
||||||
|
gotoOpcode,
|
||||||
|
IRDataType.BYTE,
|
||||||
|
reg1 = compResultReg,
|
||||||
|
value = goto.address?.toInt()
|
||||||
|
)
|
||||||
|
else if (goto.generatedLabel != null)
|
||||||
|
IRInstruction(
|
||||||
|
gotoOpcode,
|
||||||
|
IRDataType.BYTE,
|
||||||
|
reg1 = compResultReg,
|
||||||
|
labelSymbol = goto.generatedLabel
|
||||||
|
)
|
||||||
|
else
|
||||||
|
IRInstruction(
|
||||||
|
gotoOpcode,
|
||||||
|
IRDataType.BYTE,
|
||||||
|
reg1 = compResultReg,
|
||||||
|
labelSymbol = goto.identifier!!.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return result
|
||||||
} else {
|
} else {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val rightConst = condition.right.asConstInteger()
|
||||||
val condition = ifElse.condition as PtBinaryExpression
|
return if (rightConst == 0)
|
||||||
if(irDtLeft==IRDataType.FLOAT) {
|
ifZeroIntThenJump(result, ifElse, signed, irDtLeft, goto)
|
||||||
val leftTr = expressionEval.translateExpression(condition.left)
|
else {
|
||||||
addToResult(result, leftTr, -1, leftTr.resultFpReg)
|
ifNonZeroIntThenJump(result, ifElse, signed, irDtLeft, goto)
|
||||||
val rightTr = expressionEval.translateExpression(condition.right)
|
|
||||||
addToResult(result, rightTr, -1, rightTr.resultFpReg)
|
|
||||||
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 (condition.operator) {
|
|
||||||
"==" -> Opcode.BZ
|
|
||||||
"!=" -> Opcode.BNZ
|
|
||||||
"<" -> Opcode.BLEZS
|
|
||||||
">" -> Opcode.BGEZS
|
|
||||||
"<=" -> Opcode.BLZS
|
|
||||||
">=" -> Opcode.BGZS
|
|
||||||
else -> throw AssemblyError("weird operator")
|
|
||||||
}
|
|
||||||
it += if (goto.address != null)
|
|
||||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, value = goto.address?.toInt())
|
|
||||||
else if (goto.generatedLabel != null)
|
|
||||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, labelSymbol = goto.generatedLabel)
|
|
||||||
else
|
|
||||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, labelSymbol = goto.identifier!!.name)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
val rightConst = condition.right.asConstInteger()
|
|
||||||
return if(rightConst==0)
|
|
||||||
ifZeroIntThenJump(result, ifElse, signed, irDtLeft, goto)
|
|
||||||
else {
|
|
||||||
ifNonZeroIntThenJump(result, ifElse, signed, irDtLeft, goto)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ class BinExprSplitter(private val program: Program, private val options: Compila
|
|||||||
|
|
||||||
if(options.compTarget.name == VMTarget.NAME)
|
if(options.compTarget.name == VMTarget.NAME)
|
||||||
return noModifications // don't split expressions when targeting the vm codegen, it handles nested expressions well
|
return noModifications // don't split expressions when targeting the vm codegen, it handles nested expressions well
|
||||||
|
if(options.useRPN) // TODO RPN does this make a difference?
|
||||||
|
return noModifications
|
||||||
|
|
||||||
if(assignment.value.inferType(program) istype DataType.FLOAT && !options.optimizeFloatExpressions)
|
if(assignment.value.inferType(program) istype DataType.FLOAT && !options.optimizeFloatExpressions)
|
||||||
return noModifications
|
return noModifications
|
||||||
|
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,
|
outputDir: Path = prog8tests.helpers.outputDir,
|
||||||
errors: IErrorReporter? = null,
|
errors: IErrorReporter? = null,
|
||||||
writeAssembly: Boolean = true,
|
writeAssembly: Boolean = true,
|
||||||
optFloatExpr: Boolean = true
|
optFloatExpr: Boolean = true,
|
||||||
|
useRPN: Boolean = false
|
||||||
) : CompilationResult? {
|
) : CompilationResult? {
|
||||||
val filepath = fileDir.resolve(fileName)
|
val filepath = fileDir.resolve(fileName)
|
||||||
assumeReadableFile(filepath)
|
assumeReadableFile(filepath)
|
||||||
@ -31,7 +32,7 @@ internal fun compileFile(
|
|||||||
asmListfile = false,
|
asmListfile = false,
|
||||||
experimentalCodegen = false,
|
experimentalCodegen = false,
|
||||||
varsHigh = false,
|
varsHigh = false,
|
||||||
useRPN = false,
|
useRPN = useRPN,
|
||||||
platform.name,
|
platform.name,
|
||||||
evalStackBaseAddress = null,
|
evalStackBaseAddress = null,
|
||||||
symbolDefs = emptyMap(),
|
symbolDefs = emptyMap(),
|
||||||
@ -52,11 +53,12 @@ internal fun compileText(
|
|||||||
sourceText: String,
|
sourceText: String,
|
||||||
errors: IErrorReporter? = null,
|
errors: IErrorReporter? = null,
|
||||||
writeAssembly: Boolean = true,
|
writeAssembly: Boolean = true,
|
||||||
optFloatExpr: Boolean = true
|
optFloatExpr: Boolean = true,
|
||||||
|
useRPN: Boolean = false
|
||||||
) : CompilationResult? {
|
) : CompilationResult? {
|
||||||
val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8")
|
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
|
// we don't assumeNotExists(filePath) - should be ok to just overwrite it
|
||||||
filePath.toFile().writeText(sourceText)
|
filePath.toFile().writeText(sourceText)
|
||||||
return compileFile(platform, optimize, filePath.parent, filePath.name,
|
return compileFile(platform, optimize, filePath.parent, filePath.name,
|
||||||
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr)
|
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, useRPN=useRPN)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
BRANCH: Write some unit tests for the RPN.
|
BRANCH: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt
|
||||||
BRANCH: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt
|
BRANCH: check BinExprSplitter disablement any effect for RPN?
|
||||||
BRANCH: Implement RPN codegen for IR.
|
BRANCH: Implement RPN codegen for IR.
|
||||||
|
|
||||||
For next minor release
|
For next minor release
|
||||||
|
@ -1,36 +1,17 @@
|
|||||||
%import textio
|
%import math
|
||||||
%import test_stack
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
|
||||||
|
|
||||||
; $1e4 size
|
; Note: this program is compatible with C64 and CX16.
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
uword xx=4000
|
ubyte[255] BC
|
||||||
ubyte a=11
|
bool[255] DX
|
||||||
ubyte b=22
|
|
||||||
ubyte c=33
|
|
||||||
|
|
||||||
; cx16.r0 = peekw(xx+a+b+c)
|
BC[2] = math.rnd() & 15
|
||||||
; cx16.r1 = peekw(xx+a+b+c+42)
|
BC[3] = math.rnd() & 15
|
||||||
; pokew(xx+a+b+c, xx)
|
BC[4] = math.rnd() & 15
|
||||||
; pokew(xx+a+b+c+42, xx)
|
;DX[2] = math.rnd() & 1
|
||||||
|
}
|
||||||
if a and a & $40 == 0
|
|
||||||
cx16.r0++
|
|
||||||
|
|
||||||
; if cx16.r0L in "derp" {
|
|
||||||
; xx++
|
|
||||||
; }
|
|
||||||
;
|
|
||||||
; xx = xx+(3*func(xx)+xx*2*cx16.r0L)
|
|
||||||
; txt.print_uw(xx)
|
|
||||||
}
|
|
||||||
|
|
||||||
; sub func(uword value) -> uword {
|
|
||||||
; value ++
|
|
||||||
; return value
|
|
||||||
; }
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user