mirror of
https://github.com/irmen/prog8.git
synced 2024-07-05 06:29:02 +00:00
introducing IVariableAllocation (WIP)
This commit is contained in:
parent
6bdd81623f
commit
d2309b8114
@ -10,7 +10,6 @@ import prog8.ast.statements.*
|
||||
import prog8.codegen.cpu6502.assignment.*
|
||||
import prog8.compilerinterface.*
|
||||
import prog8.parser.SourceCode
|
||||
import java.nio.file.Path
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
@ -330,7 +329,7 @@ class AsmGen6502(internal val program: Program,
|
||||
if(blockname=="prog8_lib" && variable.name.startsWith("P8ZP_SCRATCH_"))
|
||||
continue // the "hooks" to the temp vars are not generated as new variables
|
||||
val scopedName = variable.scopedName
|
||||
val zpAlloc = zeropage.allocatedZeropageVariable(scopedName)
|
||||
val zpAlloc = zeropage.variables[scopedName]
|
||||
if (zpAlloc == null) {
|
||||
// This var is not on the ZP yet. Attempt to move it there if it's an integer type
|
||||
if(variable.zeropage != ZeropageWish.NOT_IN_ZEROPAGE &&
|
||||
@ -482,7 +481,7 @@ class AsmGen6502(internal val program: Program,
|
||||
.filter {
|
||||
it.type==VarDeclType.VAR
|
||||
&& it.zeropage!=ZeropageWish.REQUIRE_ZEROPAGE
|
||||
&& zeropage.allocatedZeropageVariable(it.scopedName)==null
|
||||
&& it.scopedName !in zeropage.variables
|
||||
}
|
||||
|
||||
vars.filter { it.datatype == DataType.STR && shouldActuallyOutputStringVar(it) }
|
||||
@ -1742,12 +1741,11 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
}
|
||||
|
||||
internal fun isZpVar(scopedName: List<String>): Boolean =
|
||||
zeropage.allocatedZeropageVariable(scopedName)!=null
|
||||
internal fun isZpVar(scopedName: List<String>) = scopedName in zeropage.variables
|
||||
|
||||
internal fun isZpVar(variable: IdentifierReference): Boolean {
|
||||
val vardecl = variable.targetVarDecl(program)!!
|
||||
return zeropage.allocatedZeropageVariable(vardecl.scopedName)!=null
|
||||
return vardecl.scopedName in zeropage.variables
|
||||
}
|
||||
|
||||
internal fun jmp(asmLabel: String, indirect: Boolean=false) {
|
||||
|
@ -343,13 +343,14 @@ private fun writeAssembly(program: Program,
|
||||
compilerOptions: CompilationOptions
|
||||
): WriteAssemblyResult {
|
||||
// asm generation directly from the Ast
|
||||
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
||||
program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
||||
errors.report()
|
||||
// TODO do something with the VariableAllocation, pass it to the asmgenerator
|
||||
|
||||
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||
// printProgram(program)
|
||||
|
||||
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
||||
val assembly = asmGeneratorFor(program, errors, compilerOptions).compileToAssembly()
|
||||
errors.report()
|
||||
|
||||
|
@ -1,9 +1,6 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.IStatementContainer
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.*
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
@ -18,14 +15,22 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
||||
) : AstWalker() {
|
||||
|
||||
private val allBlockVars = mutableMapOf<Block, MutableSet<VarDecl>>()
|
||||
private val allBlockConsts = mutableMapOf<Block, MutableSet<VarDecl>>()
|
||||
private val allBlockMemoryvars = mutableMapOf<Block, MutableSet<VarDecl>>()
|
||||
private val allSubroutineVars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
|
||||
// internal lateinit var allocation: IVariableAllocation
|
||||
//
|
||||
// override fun after(program: Program): Iterable<IAstModification> {
|
||||
// allocation = VariableAllocation(allBlockVars, allSubroutineVars)
|
||||
// allocation.dump(program.memsizer)
|
||||
// return super.after(program)
|
||||
// }
|
||||
private val allSubroutineConsts = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
|
||||
private val allSubroutineMemoryvars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
|
||||
internal lateinit var allocation: IVariableAllocation
|
||||
|
||||
/* TODO complete the use of VariableAllocation and get rid of it from the AsmGen (and that should no longer use vardecl either):
|
||||
override fun after(program: Program): Iterable<IAstModification> {
|
||||
allocation = VariableAllocation(options,
|
||||
allBlockVars, allBlockConsts, allBlockMemoryvars,
|
||||
allSubroutineVars, allSubroutineConsts, allSubroutineMemoryvars)
|
||||
allocation.dump(program.memsizer)
|
||||
return super.after(program)
|
||||
}
|
||||
*/
|
||||
|
||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||
throw FatalAstException("break should have been replaced by goto $breakStmt")
|
||||
@ -66,24 +71,66 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
||||
throw FatalAstException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
|
||||
}
|
||||
|
||||
if(decl.type==VarDeclType.VAR) {
|
||||
when(val scope=decl.definingScope) {
|
||||
is Block -> {
|
||||
val blockVars = allBlockVars[scope] ?: mutableSetOf()
|
||||
blockVars.add(decl)
|
||||
allBlockVars[scope] = blockVars
|
||||
val scope=decl.definingScope
|
||||
when (decl.type) {
|
||||
VarDeclType.VAR -> {
|
||||
when(scope) {
|
||||
is Block -> {
|
||||
val decls = allBlockVars[scope] ?: mutableSetOf()
|
||||
decls.add(decl)
|
||||
allBlockVars[scope] = decls
|
||||
}
|
||||
is Subroutine -> {
|
||||
val decls = allSubroutineVars[scope] ?: mutableSetOf()
|
||||
decls.add(decl)
|
||||
allSubroutineVars[scope] = decls
|
||||
}
|
||||
else -> {
|
||||
throw FatalAstException("var can only occur in subroutine or block scope")
|
||||
}
|
||||
}
|
||||
is Subroutine -> {
|
||||
val subroutineVars = allSubroutineVars[scope] ?: mutableSetOf()
|
||||
subroutineVars.add(decl)
|
||||
allSubroutineVars[scope] = subroutineVars
|
||||
}
|
||||
VarDeclType.CONST -> {
|
||||
when(scope) {
|
||||
is Block -> {
|
||||
val decls = allBlockConsts[scope] ?: mutableSetOf()
|
||||
decls.add(decl)
|
||||
allBlockConsts[scope] = decls
|
||||
}
|
||||
is Subroutine -> {
|
||||
val decls = allSubroutineConsts[scope] ?: mutableSetOf()
|
||||
decls.add(decl)
|
||||
allSubroutineConsts[scope] = decls
|
||||
}
|
||||
else -> {
|
||||
throw FatalAstException("var can only occur in subroutine or block scope")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
throw FatalAstException("var can only occur in subroutine or block scope")
|
||||
}
|
||||
VarDeclType.MEMORY -> {
|
||||
when(scope) {
|
||||
is Block -> {
|
||||
val decls = allBlockMemoryvars[scope] ?: mutableSetOf()
|
||||
decls.add(decl)
|
||||
allBlockMemoryvars[scope] = decls
|
||||
}
|
||||
is Subroutine -> {
|
||||
val decls = allSubroutineMemoryvars[scope] ?: mutableSetOf()
|
||||
decls.add(decl)
|
||||
allSubroutineMemoryvars[scope] = decls
|
||||
}
|
||||
else -> {
|
||||
throw FatalAstException("var can only occur in subroutine or block scope")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
throw FatalAstException("invalid var type")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO get rid of the vardecl inside the ast - codegen should depend on the IVariableAllocation object
|
||||
// return listOf(IAstModification.Remove(decl, parent as IStatementContainer))
|
||||
return noModifications
|
||||
}
|
||||
|
||||
@ -399,25 +446,154 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
||||
}
|
||||
|
||||
|
||||
internal class VariableAllocation(
|
||||
override val blockVars: Map<Block, Set<VarDecl>>,
|
||||
override val subroutineVars: Map<Subroutine, Set<VarDecl>>) : IVariableAllocation
|
||||
internal class VariableAllocation (
|
||||
options: CompilationOptions,
|
||||
astBlockVars: Map<Block, Set<VarDecl>>,
|
||||
astBlockConsts: Map<Block, Set<VarDecl>>,
|
||||
astBlockMemvars: Map<Block, Set<VarDecl>>,
|
||||
astSubroutineVars: Map<Subroutine, Set<VarDecl>>,
|
||||
astSubroutineConsts: Map<Subroutine, Set<VarDecl>>,
|
||||
astSubroutineMemvars: Map<Subroutine, Set<VarDecl>>
|
||||
) : IVariableAllocation
|
||||
{
|
||||
override val zeropageVars: Set<IVariableAllocation.ZeropageVariable>
|
||||
override val blockVars: Map<Block, Set<IVariableAllocation.StaticBlockVariable>>
|
||||
override val blockConsts: Map<Block, Set<IVariableAllocation.ConstantNumberSymbol>>
|
||||
override val blockMemvars: Map<Block, Set<IVariableAllocation.MemoryMappedSymbol>>
|
||||
override val subroutineVars: Map<Subroutine, Set<IVariableAllocation.StaticSubroutineVariable>>
|
||||
override val subroutineConsts: Map<Subroutine, Set<IVariableAllocation.ConstantNumberSymbol>>
|
||||
override val subroutineMemvars: Map<Subroutine, Set<IVariableAllocation.MemoryMappedSymbol>>
|
||||
|
||||
init {
|
||||
if(options.zeropage!=ZeropageType.DONTUSE)
|
||||
allocateVarsInZeropage(options.compTarget.machine.zeropage)
|
||||
|
||||
val zpv = mutableSetOf<IVariableAllocation.ZeropageVariable>()
|
||||
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariableAllocation.StaticBlockVariable>() }
|
||||
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariableAllocation.ConstantNumberSymbol>() }
|
||||
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariableAllocation.MemoryMappedSymbol>() }
|
||||
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariableAllocation.StaticSubroutineVariable>() }
|
||||
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariableAllocation.ConstantNumberSymbol>() }
|
||||
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariableAllocation.MemoryMappedSymbol>() }
|
||||
astBlockVars.forEach { (block, decls) ->
|
||||
val vars = bv.getValue(block)
|
||||
vars.addAll(decls.map {
|
||||
// TODO make sure the zp-allocated variables are not added here
|
||||
IVariableAllocation.StaticBlockVariable(it.datatype, it.name, it.value, it.position, it)
|
||||
})
|
||||
}
|
||||
astBlockConsts.forEach { (block, decls) ->
|
||||
bc.getValue(block).addAll(
|
||||
decls.map {
|
||||
IVariableAllocation.ConstantNumberSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number,
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
astBlockMemvars.forEach { (block, decls) ->
|
||||
bmv.getValue(block).addAll(
|
||||
decls.map {
|
||||
IVariableAllocation.MemoryMappedSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number.toUInt(),
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
astSubroutineVars.forEach { (sub, decls) ->
|
||||
val vars = sv.getValue(sub)
|
||||
vars.addAll(decls.map {
|
||||
// TODO make sure the zp-allocated variables are not added here
|
||||
IVariableAllocation.StaticSubroutineVariable(it.datatype, it.name, it.position, it)
|
||||
})
|
||||
}
|
||||
astSubroutineConsts.forEach { (sub, decls) ->
|
||||
sc.getValue(sub).addAll(
|
||||
decls.map {
|
||||
IVariableAllocation.ConstantNumberSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number,
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
astSubroutineMemvars.forEach { (sub, decls) ->
|
||||
smv.getValue(sub).addAll(
|
||||
decls.map {
|
||||
IVariableAllocation.MemoryMappedSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number.toUInt(),
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
zeropageVars = zpv
|
||||
blockVars = bv
|
||||
blockConsts = bc
|
||||
blockMemvars = bmv
|
||||
subroutineVars = sv
|
||||
subroutineConsts = sc
|
||||
subroutineMemvars = smv
|
||||
}
|
||||
|
||||
private fun allocateVarsInZeropage(zeropage: Zeropage) {
|
||||
println("TODO: allocate vars on zeropage") // TODO
|
||||
}
|
||||
|
||||
override fun dump(memsizer: IMemSizer) {
|
||||
println("ALL BLOCK VARS:")
|
||||
println("\nALL ZEROPAGE VARS:")
|
||||
zeropageVars.forEach {
|
||||
println(" ${it.type} ${it.scopedname} ${it.position}")
|
||||
}
|
||||
println("\nALL BLOCK VARS:")
|
||||
blockVars.forEach { (block, vars) ->
|
||||
val totalsize = vars.sumOf { memsizer.memorySize(it) }
|
||||
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }
|
||||
println("BLOCK: ${block.name} total size: $totalsize")
|
||||
vars.forEach {
|
||||
println(" ${it.datatype} ${it.name} ${it.position}")
|
||||
println(" ${it.type} ${it.name} = ${it.initialValue} ${it.position}")
|
||||
}
|
||||
}
|
||||
println("ALL SUBROUTINE VARS:")
|
||||
println("\nALL BLOCK CONSTS:")
|
||||
blockConsts.forEach { (block, vars) ->
|
||||
println("BLOCK: ${block.name}")
|
||||
vars.forEach {
|
||||
println(" ${it.type} ${it.name} = ${it.value} ${it.position}")
|
||||
}
|
||||
}
|
||||
println("\nALL BLOCK MEMORYVARS:")
|
||||
blockMemvars.forEach { (block, vars) ->
|
||||
println("BLOCK: ${block.name}")
|
||||
vars.forEach {
|
||||
println(" ${it.type} ${it.name} = ${it.address.toHex()} ${it.position}")
|
||||
}
|
||||
}
|
||||
|
||||
println("\nALL SUBROUTINE VARS:")
|
||||
subroutineVars.forEach { (sub, vars) ->
|
||||
val totalsize = vars.sumOf { memsizer.memorySize(it) }
|
||||
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }
|
||||
println("SUBROUTINE: ${sub.name} total size: $totalsize")
|
||||
vars.forEach {
|
||||
println(" ${it.datatype} ${it.name} ${it.position}")
|
||||
println(" ${it.type} ${it.name} ${it.position}")
|
||||
}
|
||||
}
|
||||
println("\nALL SUBROUTINE CONSTS:")
|
||||
subroutineConsts.forEach { (sub, vars) ->
|
||||
println("SUBROUTINE: ${sub.name}")
|
||||
vars.forEach {
|
||||
println(" ${it.type} ${it.name} = ${it.value} ${it.position}")
|
||||
}
|
||||
}
|
||||
println("\nALL SUBROUTINE MEMORYVARS:")
|
||||
subroutineMemvars.forEach { (sub, vars) ->
|
||||
println("SUBROUTINE: ${sub.name}")
|
||||
vars.forEach {
|
||||
println(" ${it.type} ${it.name} = ${it.address.toHex()} ${it.position}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,12 +259,12 @@ class TestCx16Zeropage: FunSpec({
|
||||
|
||||
test("preallocated zp vars") {
|
||||
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target))
|
||||
zp1.allocatedZeropageVariable(listOf("test")) shouldBe null
|
||||
zp1.allocatedZeropageVariable(listOf("cx16", "r0")) shouldNotBe null
|
||||
zp1.allocatedZeropageVariable(listOf("cx16", "r15")) shouldNotBe null
|
||||
zp1.allocatedZeropageVariable(listOf("cx16", "r0L")) shouldNotBe null
|
||||
zp1.allocatedZeropageVariable(listOf("cx16", "r15L")) shouldNotBe null
|
||||
zp1.allocatedZeropageVariable(listOf("cx16", "r0sH")) shouldNotBe null
|
||||
zp1.allocatedZeropageVariable(listOf("cx16", "r15sH")) shouldNotBe null
|
||||
zp1.variables[listOf("test")] shouldBe null
|
||||
zp1.variables[listOf("cx16", "r0")] shouldNotBe null
|
||||
zp1.variables[listOf("cx16", "r15")] shouldNotBe null
|
||||
zp1.variables[listOf("cx16", "r0L")] shouldNotBe null
|
||||
zp1.variables[listOf("cx16", "r15L")] shouldNotBe null
|
||||
zp1.variables[listOf("cx16", "r0sH")] shouldNotBe null
|
||||
zp1.variables[listOf("cx16", "r15sH")] shouldNotBe null
|
||||
}
|
||||
})
|
||||
|
@ -1,12 +1,27 @@
|
||||
package prog8.compilerinterface
|
||||
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.expressions.Expression
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.VarDecl
|
||||
|
||||
|
||||
interface IVariableAllocation {
|
||||
data class ConstantNumberSymbol(val type: DataType, val name: String, val value: Double, val position: Position)
|
||||
data class MemoryMappedSymbol(val type: DataType, val name: String, val address: UInt, val position: Position)
|
||||
data class StaticBlockVariable(val type: DataType, val name: String, val initialValue: Expression?, val position: Position, val origVar: VarDecl) // TODO should get rid of origVar altogether
|
||||
data class StaticSubroutineVariable(val type: DataType, val name: String, val position: Position, val origVar: VarDecl) // TODO should get rid of origVar altogether
|
||||
data class ZeropageVariable(val type: DataType, val scopedname: List<String>, val position: Position)
|
||||
|
||||
fun dump(memsizer: IMemSizer)
|
||||
|
||||
val blockVars: Map<Block, Set<VarDecl>>
|
||||
val subroutineVars: Map<Subroutine, Set<VarDecl>>
|
||||
val zeropageVars: Set<ZeropageVariable> // also present in the Zeropage object after this allocation
|
||||
val blockVars: Map<Block, Set<StaticBlockVariable>>
|
||||
val blockConsts: Map<Block, Set<ConstantNumberSymbol>>
|
||||
val blockMemvars: Map<Block, Set<MemoryMappedSymbol>>
|
||||
val subroutineVars: Map<Subroutine, Set<StaticSubroutineVariable>>
|
||||
val subroutineConsts: Map<Subroutine, Set<ConstantNumberSymbol>>
|
||||
val subroutineMemvars: Map<Subroutine, Set<MemoryMappedSymbol>>
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
||||
// name (scoped) ==> pair of address to (Datatype + bytesize)
|
||||
protected val allocatedVariables = mutableMapOf<List<String>, Pair<UInt, Pair<DataType, Int>>>()
|
||||
private val allocations = mutableMapOf<UInt, Pair<List<String>, DataType>>()
|
||||
public val variables: Map<List<String>, Pair<UInt, Pair<DataType, Int>>> = allocatedVariables
|
||||
|
||||
val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations.
|
||||
|
||||
@ -107,6 +108,4 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
||||
require(size>0)
|
||||
return free.containsAll((address until address+size.toUInt()).toList())
|
||||
}
|
||||
|
||||
fun allocatedZeropageVariable(name: List<String>): Pair<UInt, Pair<DataType, Int>>? = allocatedVariables[name]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user