mirror of
https://github.com/irmen/prog8.git
synced 2024-11-18 04:08:58 +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
|
import kotlin.io.path.writeLines
|
||||||
|
|
||||||
|
|
||||||
const val generatedLabelPrefix = "prog8_label_"
|
internal const val generatedLabelPrefix = "prog8_label_"
|
||||||
const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
|
internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
|
||||||
const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
|
internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
|
||||||
|
|
||||||
|
|
||||||
class AsmGen(internal val program: Program,
|
class AsmGen(internal val program: Program,
|
||||||
@ -124,7 +124,7 @@ class AsmGen(internal val program: Program,
|
|||||||
fun asmSymbolName(identifier: IdentifierReference) = asmSymbolName(identifier.nameInSource)
|
fun asmSymbolName(identifier: IdentifierReference) = asmSymbolName(identifier.nameInSource)
|
||||||
fun asmVariableName(identifier: IdentifierReference) = asmVariableName(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) {
|
return when(dt) {
|
||||||
DataType.UBYTE -> listOf("cx16", "r9L")
|
DataType.UBYTE -> listOf("cx16", "r9L")
|
||||||
DataType.BYTE -> listOf("cx16", "r9sL")
|
DataType.BYTE -> listOf("cx16", "r9sL")
|
||||||
@ -330,7 +330,6 @@ class AsmGen(internal val program: Program,
|
|||||||
internal fun translate(stmt: Statement) {
|
internal fun translate(stmt: Statement) {
|
||||||
outputSourceLine(stmt)
|
outputSourceLine(stmt)
|
||||||
when(stmt) {
|
when(stmt) {
|
||||||
is VarDecl -> translate(stmt)
|
|
||||||
is Directive -> translate(stmt)
|
is Directive -> translate(stmt)
|
||||||
is Return -> translate(stmt)
|
is Return -> translate(stmt)
|
||||||
is Subroutine -> programGen.translateSubroutine(stmt)
|
is Subroutine -> programGen.translateSubroutine(stmt)
|
||||||
@ -359,6 +358,7 @@ class AsmGen(internal val program: Program,
|
|||||||
is When -> translate(stmt)
|
is When -> translate(stmt)
|
||||||
is AnonymousScope -> translate(stmt)
|
is AnonymousScope -> translate(stmt)
|
||||||
is Pipe -> translatePipeExpression(stmt.expressions, stmt, true, false)
|
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 BuiltinFunctionPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore")
|
||||||
is UntilLoop -> throw AssemblyError("do..until should have been converted to jumps")
|
is UntilLoop -> throw AssemblyError("do..until should have been converted to jumps")
|
||||||
is WhileLoop -> throw AssemblyError("while 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) {
|
private fun translate(stmt: Directive) {
|
||||||
when(stmt.directive) {
|
when(stmt.directive) {
|
||||||
"%asminclude" -> {
|
"%asminclude" -> {
|
||||||
|
@ -10,7 +10,7 @@ import prog8.compilerinterface.IMachineDefinition
|
|||||||
// note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations
|
// 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
|
var numberOfOptimizations = 0
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import kotlin.io.path.Path
|
|||||||
import kotlin.io.path.isRegularFile
|
import kotlin.io.path.isRegularFile
|
||||||
|
|
||||||
|
|
||||||
class AssemblyProgram(
|
internal class AssemblyProgram(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
outputDir: Path,
|
outputDir: Path,
|
||||||
private val compTarget: ICompilationTarget) : IAssemblyProgram {
|
private val compTarget: ICompilationTarget) : IAssemblyProgram {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package prog8.codegen.cpu6502
|
package prog8.codegen.cpu6502
|
||||||
|
|
||||||
import com.github.michaelbull.result.fold
|
import com.github.michaelbull.result.fold
|
||||||
import com.github.michaelbull.result.onSuccess
|
|
||||||
import prog8.ast.IFunctionCall
|
import prog8.ast.IFunctionCall
|
||||||
import prog8.ast.IStatementContainer
|
import prog8.ast.IStatementContainer
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
@ -28,7 +27,7 @@ internal class ProgramGen(
|
|||||||
) {
|
) {
|
||||||
private val compTarget = options.compTarget
|
private val compTarget = options.compTarget
|
||||||
private val removals = mutableListOf<Pair<Statement, IStatementContainer>>()
|
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 callGraph = CallGraph(program)
|
||||||
private val blockVariableInitializers = program.allBlocks.associateWith { it.statements.filterIsInstance<Assignment>() }
|
private val blockVariableInitializers = program.allBlocks.associateWith { it.statements.filterIsInstance<Assignment>() }
|
||||||
|
|
||||||
@ -43,7 +42,7 @@ internal class ProgramGen(
|
|||||||
if(allBlocks.first().name != "main")
|
if(allBlocks.first().name != "main")
|
||||||
throw AssemblyError("first block should be 'main'")
|
throw AssemblyError("first block should be 'main'")
|
||||||
|
|
||||||
allocateAllZeropageVariables()
|
allocation.allocateAllZeropageVariables(options, callGraph)
|
||||||
if(errors.noErrors()) {
|
if(errors.noErrors()) {
|
||||||
program.allBlocks.forEach { block2asm(it) }
|
program.allBlocks.forEach { block2asm(it) }
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ internal class ProgramGen(
|
|||||||
removals.remove(removal)
|
removals.remove(removal)
|
||||||
}
|
}
|
||||||
|
|
||||||
slaballocations()
|
memorySlabs()
|
||||||
footer()
|
footer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +133,7 @@ internal class ProgramGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun slaballocations() {
|
private fun memorySlabs() {
|
||||||
asmgen.out("; memory slabs")
|
asmgen.out("; memory slabs")
|
||||||
asmgen.out("prog8_slabs\t.block")
|
asmgen.out("prog8_slabs\t.block")
|
||||||
for((name, info) in asmgen.allMemorySlabs) {
|
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
|
// 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 stringVarsInZp = allocation.varsInZeropage.filter { it.datatype==DataType.STR && it.value!=null }
|
||||||
val arrayVarsInZp = varsInZeropage.filter { it.datatype in ArrayDatatypes && it.value!=null }
|
val arrayVarsInZp = allocation.varsInZeropage.filter { it.datatype in ArrayDatatypes && it.value!=null }
|
||||||
if(stringVarsInZp.isNotEmpty() || arrayVarsInZp.isNotEmpty()) {
|
if(stringVarsInZp.isNotEmpty() || arrayVarsInZp.isNotEmpty()) {
|
||||||
asmgen.out("; zp str and array initializations")
|
asmgen.out("; zp str and array initializations")
|
||||||
stringVarsInZp.forEach {
|
stringVarsInZp.forEach {
|
||||||
@ -354,54 +353,6 @@ internal class ProgramGen(
|
|||||||
clc""")
|
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?) {
|
private fun zeropagevars2asm(statements: List<Statement>, inBlock: Block?) {
|
||||||
asmgen.out("; vars allocated on zeropage")
|
asmgen.out("; vars allocated on zeropage")
|
||||||
val variables = statements.asSequence().filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR }
|
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
|
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 {
|
override fun assemble(options: CompilationOptions): Boolean {
|
||||||
println("..todo: assemble code into binary..")
|
println("..todo: assemble code into binary..")
|
||||||
|
Loading…
Reference in New Issue
Block a user