mirror of
https://github.com/irmen/prog8.git
synced 2025-01-08 22:32:06 +00:00
start to rewrite variable allocation
This commit is contained in:
parent
72dfb0bda3
commit
9acc2f92d1
@ -13,9 +13,9 @@ import kotlin.io.path.Path
|
||||
import kotlin.io.path.writeLines
|
||||
|
||||
|
||||
const val generatedLabelPrefix = "prog8_label_"
|
||||
const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
|
||||
const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
|
||||
internal const val generatedLabelPrefix = "prog8_label_"
|
||||
internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
|
||||
internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
|
||||
|
||||
|
||||
class AsmGen(internal val program: Program,
|
||||
@ -124,7 +124,7 @@ class AsmGen(internal val program: Program,
|
||||
fun asmSymbolName(identifier: IdentifierReference) = asmSymbolName(identifier.nameInSource)
|
||||
fun asmVariableName(identifier: IdentifierReference) = asmVariableName(identifier.nameInSource)
|
||||
|
||||
fun getTempVarName(dt: DataType): List<String> {
|
||||
internal fun getTempVarName(dt: DataType): List<String> {
|
||||
return when(dt) {
|
||||
DataType.UBYTE -> listOf("cx16", "r9L")
|
||||
DataType.BYTE -> listOf("cx16", "r9sL")
|
||||
@ -330,7 +330,6 @@ class AsmGen(internal val program: Program,
|
||||
internal fun translate(stmt: Statement) {
|
||||
outputSourceLine(stmt)
|
||||
when(stmt) {
|
||||
is VarDecl -> translate(stmt)
|
||||
is Directive -> translate(stmt)
|
||||
is Return -> translate(stmt)
|
||||
is Subroutine -> programGen.translateSubroutine(stmt)
|
||||
@ -359,6 +358,7 @@ class AsmGen(internal val program: Program,
|
||||
is When -> translate(stmt)
|
||||
is AnonymousScope -> translate(stmt)
|
||||
is Pipe -> translatePipeExpression(stmt.expressions, stmt, true, false)
|
||||
is VarDecl -> { /* do nothing; variables are handled elsewhere */ }
|
||||
is BuiltinFunctionPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore")
|
||||
is UntilLoop -> throw AssemblyError("do..until should have been converted to jumps")
|
||||
is WhileLoop -> throw AssemblyError("while should have been converted to jumps")
|
||||
@ -882,12 +882,6 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
}
|
||||
|
||||
private fun translate(decl: VarDecl) {
|
||||
if(decl.type==VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
|
||||
throw AssemblyError("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
|
||||
// at this time, nothing has to be done here anymore code-wise
|
||||
}
|
||||
|
||||
private fun translate(stmt: Directive) {
|
||||
when(stmt.directive) {
|
||||
"%asminclude" -> {
|
||||
|
@ -10,7 +10,7 @@ import prog8.compilerinterface.IMachineDefinition
|
||||
// note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations
|
||||
|
||||
|
||||
fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefinition, program: Program): Int {
|
||||
internal fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefinition, program: Program): Int {
|
||||
|
||||
var numberOfOptimizations = 0
|
||||
|
||||
|
@ -11,7 +11,7 @@ import kotlin.io.path.Path
|
||||
import kotlin.io.path.isRegularFile
|
||||
|
||||
|
||||
class AssemblyProgram(
|
||||
internal class AssemblyProgram(
|
||||
override val name: String,
|
||||
outputDir: Path,
|
||||
private val compTarget: ICompilationTarget) : IAssemblyProgram {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package prog8.codegen.cpu6502
|
||||
|
||||
import com.github.michaelbull.result.fold
|
||||
import com.github.michaelbull.result.onSuccess
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.IStatementContainer
|
||||
import prog8.ast.Program
|
||||
@ -28,7 +27,7 @@ internal class ProgramGen(
|
||||
) {
|
||||
private val compTarget = options.compTarget
|
||||
private val removals = mutableListOf<Pair<Statement, IStatementContainer>>()
|
||||
private val varsInZeropage = mutableSetOf<VarDecl>()
|
||||
private val allocation = VariableAllocation(variables, errors)
|
||||
private val callGraph = CallGraph(program)
|
||||
private val blockVariableInitializers = program.allBlocks.associateWith { it.statements.filterIsInstance<Assignment>() }
|
||||
|
||||
@ -43,7 +42,7 @@ internal class ProgramGen(
|
||||
if(allBlocks.first().name != "main")
|
||||
throw AssemblyError("first block should be 'main'")
|
||||
|
||||
allocateAllZeropageVariables()
|
||||
allocation.allocateAllZeropageVariables(options, callGraph)
|
||||
if(errors.noErrors()) {
|
||||
program.allBlocks.forEach { block2asm(it) }
|
||||
|
||||
@ -52,7 +51,7 @@ internal class ProgramGen(
|
||||
removals.remove(removal)
|
||||
}
|
||||
|
||||
slaballocations()
|
||||
memorySlabs()
|
||||
footer()
|
||||
}
|
||||
}
|
||||
@ -134,7 +133,7 @@ internal class ProgramGen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun slaballocations() {
|
||||
private fun memorySlabs() {
|
||||
asmgen.out("; memory slabs")
|
||||
asmgen.out("prog8_slabs\t.block")
|
||||
for((name, info) in asmgen.allMemorySlabs) {
|
||||
@ -307,8 +306,8 @@ internal class ProgramGen(
|
||||
}
|
||||
|
||||
// string and array variables in zeropage that have initializer value, should be initialized
|
||||
val stringVarsInZp = varsInZeropage.filter { it.datatype==DataType.STR && it.value!=null }
|
||||
val arrayVarsInZp = varsInZeropage.filter { it.datatype in ArrayDatatypes && it.value!=null }
|
||||
val stringVarsInZp = allocation.varsInZeropage.filter { it.datatype==DataType.STR && it.value!=null }
|
||||
val arrayVarsInZp = allocation.varsInZeropage.filter { it.datatype in ArrayDatatypes && it.value!=null }
|
||||
if(stringVarsInZp.isNotEmpty() || arrayVarsInZp.isNotEmpty()) {
|
||||
asmgen.out("; zp str and array initializations")
|
||||
stringVarsInZp.forEach {
|
||||
@ -354,54 +353,6 @@ internal class ProgramGen(
|
||||
clc""")
|
||||
}
|
||||
|
||||
private fun allocateAllZeropageVariables() {
|
||||
if(options.zeropage==ZeropageType.DONTUSE)
|
||||
return
|
||||
val allVariables = this.callGraph.allIdentifiers.asSequence()
|
||||
.map { it.value }
|
||||
.filterIsInstance<VarDecl>()
|
||||
.filter { it.type==VarDeclType.VAR }
|
||||
.toSet()
|
||||
.map { it to it.scopedName }
|
||||
val varsRequiringZp = allVariables.filter { it.first.zeropage==ZeropageWish.REQUIRE_ZEROPAGE }
|
||||
val varsPreferringZp = allVariables
|
||||
.filter { it.first.zeropage==ZeropageWish.PREFER_ZEROPAGE }
|
||||
.sortedBy { options.compTarget.memorySize(it.first.datatype) } // allocate the smallest DT first
|
||||
|
||||
for ((vardecl, scopedname) in varsRequiringZp) {
|
||||
val numElements: Int? = when(vardecl.datatype) {
|
||||
DataType.STR -> {
|
||||
(vardecl.value as StringLiteralValue).value.length
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
vardecl.arraysize!!.constIndex()
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
val result = asmgen.zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.position, errors)
|
||||
result.fold(
|
||||
success = { varsInZeropage.add(vardecl) },
|
||||
failure = { errors.err(it.message!!, vardecl.position) }
|
||||
)
|
||||
}
|
||||
if(errors.noErrors()) {
|
||||
varsPreferringZp.forEach { (vardecl, scopedname) ->
|
||||
val arraySize: Int? = when (vardecl.datatype) {
|
||||
DataType.STR -> {
|
||||
(vardecl.value as StringLiteralValue).value.length
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
vardecl.arraysize!!.constIndex()
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
val result = asmgen.zeropage.allocate(scopedname, vardecl.datatype, arraySize, vardecl.position, errors)
|
||||
result.onSuccess { varsInZeropage.add(vardecl) }
|
||||
// no need to check for error, if there is one, just allocate in normal system ram later.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun zeropagevars2asm(statements: List<Statement>, inBlock: Block?) {
|
||||
asmgen.out("; vars allocated on zeropage")
|
||||
val variables = statements.asSequence().filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR }
|
||||
|
@ -0,0 +1,66 @@
|
||||
package prog8.codegen.cpu6502
|
||||
|
||||
import com.github.michaelbull.result.fold
|
||||
import com.github.michaelbull.result.onSuccess
|
||||
import prog8.ast.base.ArrayDatatypes
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.expressions.StringLiteralValue
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.ast.statements.ZeropageWish
|
||||
import prog8.compilerinterface.*
|
||||
|
||||
|
||||
internal class VariableAllocation(val vars: IVariablesAndConsts, val errors: IErrorReporter) {
|
||||
val varsInZeropage = mutableSetOf<VarDecl>()
|
||||
|
||||
fun allocateAllZeropageVariables(options: CompilationOptions, callGraph: CallGraph) {
|
||||
if(options.zeropage== ZeropageType.DONTUSE)
|
||||
return
|
||||
|
||||
val zeropage = options.compTarget.machine.zeropage
|
||||
val allVariables = callGraph.allIdentifiers.asSequence()
|
||||
.map { it.value }
|
||||
.filterIsInstance<VarDecl>()
|
||||
.filter { it.type== VarDeclType.VAR }
|
||||
.toSet()
|
||||
.map { it to it.scopedName }
|
||||
val varsRequiringZp = allVariables.filter { it.first.zeropage== ZeropageWish.REQUIRE_ZEROPAGE }
|
||||
val varsPreferringZp = allVariables
|
||||
.filter { it.first.zeropage== ZeropageWish.PREFER_ZEROPAGE }
|
||||
.sortedBy { options.compTarget.memorySize(it.first.datatype) } // allocate the smallest DT first
|
||||
|
||||
for ((vardecl, scopedname) in varsRequiringZp) {
|
||||
val numElements: Int? = when(vardecl.datatype) {
|
||||
DataType.STR -> {
|
||||
(vardecl.value as StringLiteralValue).value.length
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
vardecl.arraysize!!.constIndex()
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
val result = zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.position, errors)
|
||||
result.fold(
|
||||
success = { varsInZeropage.add(vardecl) },
|
||||
failure = { errors.err(it.message!!, vardecl.position) }
|
||||
)
|
||||
}
|
||||
if(errors.noErrors()) {
|
||||
varsPreferringZp.forEach { (vardecl, scopedname) ->
|
||||
val arraySize: Int? = when (vardecl.datatype) {
|
||||
DataType.STR -> {
|
||||
(vardecl.value as StringLiteralValue).value.length
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
vardecl.arraysize!!.constIndex()
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
val result = zeropage.allocate(scopedname, vardecl.datatype, arraySize, vardecl.position, errors)
|
||||
result.onSuccess { varsInZeropage.add(vardecl) }
|
||||
// no need to check for error, if there is one, just allocate in normal system ram later.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ import prog8.compilerinterface.CompilationOptions
|
||||
import prog8.compilerinterface.IAssemblyProgram
|
||||
|
||||
|
||||
class AssemblyProgram(override val name: String) : IAssemblyProgram
|
||||
internal class AssemblyProgram(override val name: String) : IAssemblyProgram
|
||||
{
|
||||
override fun assemble(options: CompilationOptions): Boolean {
|
||||
println("..todo: assemble code into binary..")
|
||||
|
Loading…
Reference in New Issue
Block a user