mirror of
https://github.com/irmen/prog8.git
synced 2025-01-26 19:30:59 +00:00
cleanups
This commit is contained in:
parent
f3c52c409f
commit
98b2855b9c
@ -211,7 +211,7 @@ class AsmGen(internal val program: Program,
|
||||
|
||||
private fun fixNameSymbols(name: String): String {
|
||||
val name2 = name.replace("<", "prog8_").replace(">", "") // take care of the autogenerated invalid (anon) label names
|
||||
return name2.replace("prog8_lib.P8ZP_SCRATCH_", "P8ZP_SCRATCH_") // take care of the 'hooks' to the temp vars
|
||||
return name2.replace("prog8_lib.P8ZP_SCRATCH_", "P8ZP_SCRATCH_") // take care of the 'hooks' to the temp vars -> reference zp symbols directly
|
||||
}
|
||||
|
||||
internal fun saveRegisterLocal(register: CpuRegister, scope: Subroutine) {
|
||||
|
@ -166,7 +166,7 @@ internal class ProgramGen(
|
||||
zeropagevars2asm(vardecls)
|
||||
memdefs2asmVars(vardecls, block)
|
||||
memdefs2asmAsmsubs(block.statements.filterIsInstance<Subroutine>())
|
||||
vardecls2asm(vardecls, block)
|
||||
vardecls2asm(vardecls)
|
||||
|
||||
vardecls.forEach {
|
||||
if(it.type== VarDeclType.VAR && it.datatype in NumericDatatypes)
|
||||
@ -278,7 +278,7 @@ internal class ProgramGen(
|
||||
asmgen.out("$subroutineFloatEvalResultVar1 .byte 0,0,0,0,0")
|
||||
if(asmGenInfo.usedFloatEvalResultVar2)
|
||||
asmgen.out("$subroutineFloatEvalResultVar2 .byte 0,0,0,0,0")
|
||||
vardecls2asm(vardecls, null)
|
||||
vardecls2asm(vardecls)
|
||||
asmgen.out(" .pend\n")
|
||||
}
|
||||
}
|
||||
@ -472,11 +472,10 @@ internal class ProgramGen(
|
||||
vardecls
|
||||
.filter { it.type==VarDeclType.MEMORY || it.type==VarDeclType.CONST }
|
||||
.forEach { mv ->
|
||||
if(blockname!="prog8_lib" || !mv.name.startsWith("P8ZP_SCRATCH_")) // the "hooks" to the temp vars are not generated as new variables
|
||||
if(mv.value is NumericLiteralValue)
|
||||
asmgen.out(" ${mv.name} = ${(mv.value as NumericLiteralValue).number.toHex()}")
|
||||
else
|
||||
asmgen.out(" ${mv.name} = ${asmgen.asmVariableName((mv.value as AddressOf).identifier)}")
|
||||
if(mv.value is NumericLiteralValue)
|
||||
asmgen.out(" ${mv.name} = ${(mv.value as NumericLiteralValue).number.toHex()}")
|
||||
else
|
||||
asmgen.out(" ${mv.name} = ${asmgen.asmVariableName((mv.value as AddressOf).identifier)}")
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,7 +492,7 @@ internal class ProgramGen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun vardecls2asm(vardecls: List<VarDecl>, inBlock: Block?) {
|
||||
private fun vardecls2asm(vardecls: List<VarDecl>) {
|
||||
asmgen.out("\n; non-zeropage variables")
|
||||
val vars = vardecls.filter {
|
||||
it.type==VarDeclType.VAR
|
||||
@ -504,15 +503,10 @@ internal class ProgramGen(
|
||||
vars.filter { it.datatype == DataType.STR && shouldActuallyOutputStringVar(it) }
|
||||
.forEach { outputStringvar(it) }
|
||||
|
||||
// non-string variables
|
||||
val blockname = inBlock?.name
|
||||
|
||||
vars.filter{ it.datatype != DataType.STR }.sortedBy { it.datatype }.forEach {
|
||||
require(it.zeropage!= ZeropageWish.REQUIRE_ZEROPAGE)
|
||||
if(!asmgen.isZpVar(it.scopedName)) {
|
||||
if(blockname!="prog8_lib" || !it.name.startsWith("P8ZP_SCRATCH_")) // the "hooks" to the temp vars are not generated as new variables
|
||||
vardecl2asm(it)
|
||||
}
|
||||
if(!asmgen.isZpVar(it.scopedName))
|
||||
vardecl2asm(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,25 +30,11 @@ internal class VariableAllocator(val vars: IVariablesAndConsts, val errors: IErr
|
||||
if(options.zeropage== ZeropageType.DONTUSE)
|
||||
return
|
||||
|
||||
val allVariables = (
|
||||
vars.blockVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName} +
|
||||
vars.subroutineVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName})
|
||||
.toList()
|
||||
// TODO now some HACKS to get rid of some unused vars in Petaxian - otherwise the executable gets larger than $45e8
|
||||
.filterNot { it.second.last() == "tbl" } // TODO HACK -- NOT REALLY NECESSARY, BUT OLD CallGraph DIDN'T CONTAIN IT EITHER
|
||||
.filterNot { it.second.last() in setOf("retval_interm_w", "retval_interm_b", "retval_interm_w2", "retval_interm_b2") } // TODO HACK TO REMOVE THESE UNUSED VARS
|
||||
|
||||
val zeropage = options.compTarget.machine.zeropage
|
||||
|
||||
fun numArrayElements(vardecl: VarDecl): Int? = when(vardecl.datatype) {
|
||||
DataType.STR -> {
|
||||
(vardecl.value as StringLiteralValue).value.length
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
vardecl.arraysize!!.constIndex()
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
val allVariables = (
|
||||
vars.blockVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName} +
|
||||
vars.subroutineVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName})
|
||||
.toList()
|
||||
|
||||
val varsRequiringZp = allVariables.filter { it.first.zeropage == ZeropageWish.REQUIRE_ZEROPAGE }
|
||||
val varsPreferringZp = allVariables.filter { it.first.zeropage == ZeropageWish.PREFER_ZEROPAGE }
|
||||
@ -82,6 +68,16 @@ internal class VariableAllocator(val vars: IVariablesAndConsts, val errors: IErr
|
||||
}
|
||||
}
|
||||
|
||||
private fun numArrayElements(vardecl: VarDecl): Int? = when(vardecl.datatype) {
|
||||
DataType.STR -> {
|
||||
(vardecl.value as StringLiteralValue).value.length
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
vardecl.arraysize!!.constIndex()
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun subroutineExtra(sub: Subroutine): SubroutineExtraAsmInfo {
|
||||
var extra = subroutineExtras[sub]
|
||||
return if(extra==null) {
|
||||
|
@ -344,7 +344,8 @@ private fun writeAssembly(program: Program,
|
||||
): WriteAssemblyResult {
|
||||
// asm generation directly from the Ast
|
||||
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
||||
val variables = program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
||||
val variables = VariableExtractor().extractVars(program)
|
||||
program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
||||
errors.report()
|
||||
|
||||
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||
|
@ -13,7 +13,6 @@ import prog8.ast.walk.IAstModification
|
||||
import prog8.compilerinterface.CompilationOptions
|
||||
import prog8.compilerinterface.IErrorReporter
|
||||
import prog8.compilerinterface.IStringEncoding
|
||||
import prog8.compilerinterface.IVariablesAndConsts
|
||||
|
||||
|
||||
internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) {
|
||||
@ -24,7 +23,7 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
|
||||
checker.visit(this)
|
||||
}
|
||||
|
||||
internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter): IVariablesAndConsts {
|
||||
internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter) {
|
||||
val fixer = BeforeAsmAstChanger(this, compilerOptions, errors)
|
||||
fixer.visit(this)
|
||||
while(errors.noErrors() && fixer.applyModifications()>0) {
|
||||
@ -35,7 +34,6 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
|
||||
while(errors.noErrors() && cleaner.applyModifications()>0) {
|
||||
cleaner.visit(this)
|
||||
}
|
||||
return fixer.variables
|
||||
}
|
||||
|
||||
internal fun Program.reorderStatements(errors: IErrorReporter, options: CompilationOptions) {
|
||||
|
@ -10,25 +10,11 @@ import prog8.ast.walk.IAstVisitor
|
||||
import prog8.compilerinterface.*
|
||||
import prog8.optimizer.getTempVarName
|
||||
|
||||
internal class BeforeAsmAstChanger(val program: Program, private val options: CompilationOptions,
|
||||
internal class BeforeAsmAstChanger(val program: Program,
|
||||
private val options: CompilationOptions,
|
||||
private val errors: IErrorReporter
|
||||
) : 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>>()
|
||||
private val allSubroutineConsts = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
|
||||
private val allSubroutineMemoryvars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
|
||||
internal lateinit var variables: IVariablesAndConsts
|
||||
|
||||
override fun after(program: Program): Iterable<IAstModification> {
|
||||
variables = VariablesAndConsts(
|
||||
allBlockVars, allBlockConsts, allBlockMemoryvars,
|
||||
allSubroutineVars, allSubroutineConsts, allSubroutineMemoryvars)
|
||||
return super.after(program)
|
||||
}
|
||||
|
||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||
throw FatalAstException("break should have been replaced by goto $breakStmt")
|
||||
}
|
||||
@ -68,66 +54,6 @@ 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")
|
||||
}
|
||||
|
||||
val scope=decl.definingScope
|
||||
when (decl.type) {
|
||||
VarDeclType.VAR -> {
|
||||
if(decl.origin!=VarDeclOrigin.SUBROUTINEPARAM) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
@ -443,140 +369,3 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal class VariablesAndConsts (
|
||||
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>>
|
||||
) : IVariablesAndConsts
|
||||
{
|
||||
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticBlockVariable>>
|
||||
override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
|
||||
override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
|
||||
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticSubroutineVariable>>
|
||||
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
|
||||
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
|
||||
|
||||
init {
|
||||
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticBlockVariable>() }
|
||||
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
|
||||
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
|
||||
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticSubroutineVariable>() }
|
||||
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
|
||||
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
|
||||
astBlockVars.forEach { (block, decls) ->
|
||||
val vars = bv.getValue(block)
|
||||
vars.addAll(decls.map {
|
||||
IVariablesAndConsts.StaticBlockVariable(it.datatype, it.name, it.value, it.zeropage, it.position, it)
|
||||
})
|
||||
}
|
||||
astBlockConsts.forEach { (block, decls) ->
|
||||
bc.getValue(block).addAll(
|
||||
decls.map {
|
||||
IVariablesAndConsts.ConstantNumberSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number,
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
astBlockMemvars.forEach { (block, decls) ->
|
||||
bmv.getValue(block).addAll(
|
||||
decls.map {
|
||||
IVariablesAndConsts.MemoryMappedVariable(
|
||||
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 {
|
||||
IVariablesAndConsts.StaticSubroutineVariable(it.datatype, it.name, it.zeropage, it.position, it)
|
||||
})
|
||||
}
|
||||
astSubroutineConsts.forEach { (sub, decls) ->
|
||||
sc.getValue(sub).addAll(
|
||||
decls.map {
|
||||
IVariablesAndConsts.ConstantNumberSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number,
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
astSubroutineMemvars.forEach { (sub, decls) ->
|
||||
smv.getValue(sub).addAll(
|
||||
decls.map {
|
||||
IVariablesAndConsts.MemoryMappedVariable(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number.toUInt(),
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
blockVars = bv
|
||||
blockConsts = bc
|
||||
blockMemvars = bmv
|
||||
subroutineVars = sv
|
||||
subroutineConsts = sc
|
||||
subroutineMemvars = smv
|
||||
}
|
||||
|
||||
override fun dump(memsizer: IMemSizer) {
|
||||
println("\nALL BLOCK VARS:")
|
||||
blockVars.forEach { (block, vars) ->
|
||||
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }
|
||||
println("BLOCK: ${block.name} total size: $totalsize")
|
||||
vars.forEach {
|
||||
println(" ${it.type} ${it.name} = ${it.initialValue} ${it.position}")
|
||||
}
|
||||
}
|
||||
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.origVar) }
|
||||
println("SUBROUTINE: ${sub.name} total size: $totalsize")
|
||||
vars.forEach {
|
||||
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}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
235
compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt
Normal file
235
compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt
Normal file
@ -0,0 +1,235 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.ast.statements.VarDeclOrigin
|
||||
import prog8.ast.toHex
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.compilerinterface.IMemSizer
|
||||
import prog8.compilerinterface.IVariablesAndConsts
|
||||
|
||||
|
||||
internal class VariableExtractor: IAstVisitor {
|
||||
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>>()
|
||||
private val allSubroutineConsts = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
|
||||
private val allSubroutineMemoryvars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
|
||||
|
||||
fun extractVars(program: Program): IVariablesAndConsts {
|
||||
this.visit(program)
|
||||
return VariablesAndConsts(
|
||||
allBlockVars, allBlockConsts, allBlockMemoryvars,
|
||||
allSubroutineVars, allSubroutineConsts, allSubroutineMemoryvars)
|
||||
}
|
||||
|
||||
override fun visit(decl: VarDecl) {
|
||||
val scope=decl.definingScope
|
||||
when (decl.type) {
|
||||
VarDeclType.VAR -> {
|
||||
if(decl.origin!= VarDeclOrigin.SUBROUTINEPARAM) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
super.visit(decl)
|
||||
}
|
||||
}
|
||||
|
||||
internal class VariablesAndConsts (
|
||||
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>>
|
||||
) : IVariablesAndConsts
|
||||
{
|
||||
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticBlockVariable>>
|
||||
override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
|
||||
override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
|
||||
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticSubroutineVariable>>
|
||||
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
|
||||
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
|
||||
|
||||
init {
|
||||
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticBlockVariable>() }
|
||||
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
|
||||
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
|
||||
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticSubroutineVariable>() }
|
||||
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
|
||||
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
|
||||
astBlockVars.forEach { (block, decls) ->
|
||||
val vars = bv.getValue(block)
|
||||
vars.addAll(decls.map {
|
||||
IVariablesAndConsts.StaticBlockVariable(it.datatype, it.name, it.value, it.zeropage, it.position, it)
|
||||
})
|
||||
}
|
||||
astBlockConsts.forEach { (block, decls) ->
|
||||
bc.getValue(block).addAll(
|
||||
decls.map {
|
||||
IVariablesAndConsts.ConstantNumberSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number,
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
astBlockMemvars.forEach { (block, decls) ->
|
||||
val vars = bmv.getValue(block)
|
||||
for(decl in decls) {
|
||||
// make sure the 'stubs' for the scratch variables in zeropage are not included as normal variables
|
||||
if(!decl.name.startsWith("P8ZP_SCRATCH_")) {
|
||||
vars.add(
|
||||
IVariablesAndConsts.MemoryMappedVariable(
|
||||
decl.datatype,
|
||||
decl.name,
|
||||
(decl.value as NumericLiteralValue).number.toUInt(),
|
||||
decl.position
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
astSubroutineVars.forEach { (sub, decls) ->
|
||||
val vars = sv.getValue(sub)
|
||||
vars.addAll(decls.map {
|
||||
IVariablesAndConsts.StaticSubroutineVariable(it.datatype, it.name, it.zeropage, it.position, it)
|
||||
})
|
||||
}
|
||||
astSubroutineConsts.forEach { (sub, decls) ->
|
||||
sc.getValue(sub).addAll(
|
||||
decls.map {
|
||||
IVariablesAndConsts.ConstantNumberSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number,
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
astSubroutineMemvars.forEach { (sub, decls) ->
|
||||
smv.getValue(sub).addAll(
|
||||
decls.map {
|
||||
IVariablesAndConsts.MemoryMappedVariable(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number.toUInt(),
|
||||
it.position
|
||||
)
|
||||
})
|
||||
}
|
||||
blockVars = bv
|
||||
blockConsts = bc
|
||||
blockMemvars = bmv
|
||||
subroutineVars = sv
|
||||
subroutineConsts = sc
|
||||
subroutineMemvars = smv
|
||||
}
|
||||
|
||||
override fun dump(memsizer: IMemSizer) {
|
||||
println("\nALL BLOCK VARS:")
|
||||
blockVars.forEach { (block, vars) ->
|
||||
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }
|
||||
println("BLOCK: ${block.name} total size: $totalsize")
|
||||
vars.forEach {
|
||||
println(" ${it.type} ${it.name} = ${it.initialValue} ${it.position}")
|
||||
}
|
||||
}
|
||||
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.origVar) }
|
||||
println("SUBROUTINE: ${sub.name} total size: $totalsize")
|
||||
vars.forEach {
|
||||
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}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import prog8.ast.base.Position
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.codegen.target.C64Target
|
||||
import prog8.compiler.astprocessing.VariableExtractor
|
||||
import prog8.compiler.astprocessing.processAstBeforeAsmGeneration
|
||||
import prog8.compiler.printProgram
|
||||
import prog8.compilerinterface.CompilationOptions
|
||||
@ -289,6 +290,7 @@ class TestOptimization: FunSpec({
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target(), false, src, writeAssembly = false).assertSuccess()
|
||||
val variables = VariableExtractor().extractVars(result.program)
|
||||
|
||||
// bb = (( not bb as uword) or not ww)
|
||||
val bbAssign = result.program.entrypoint.statements.last() as Assignment
|
||||
@ -301,7 +303,7 @@ class TestOptimization: FunSpec({
|
||||
expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
|
||||
val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, true, C64Target(), outputDir= outputDir)
|
||||
val allocation = result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
|
||||
result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
|
||||
|
||||
// assignment is now split into:
|
||||
// bb = not bb
|
||||
@ -326,7 +328,7 @@ class TestOptimization: FunSpec({
|
||||
((bbAssigns1expr.right as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("ww")
|
||||
bbAssigns1expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
|
||||
val asm = generateAssembly(result.program, allocation, options)
|
||||
val asm = generateAssembly(result.program, variables, options)
|
||||
asm shouldNotBe null
|
||||
asm!!.name.shouldNotBeBlank()
|
||||
}
|
||||
|
@ -83,11 +83,11 @@ internal fun compileText(
|
||||
|
||||
internal fun generateAssembly(
|
||||
program: Program,
|
||||
allocation: IVariablesAndConsts,
|
||||
variables: IVariablesAndConsts,
|
||||
options: CompilationOptions? = null
|
||||
): IAssemblyProgram? {
|
||||
val coptions = options ?: CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, true, C64Target(), outputDir = outputDir)
|
||||
coptions.compTarget.machine.zeropage = C64Zeropage(coptions)
|
||||
val asmgen = AsmGen(program, ErrorReporterForTests(), allocation, coptions)
|
||||
val asmgen = AsmGen(program, ErrorReporterForTests(), variables, coptions)
|
||||
return asmgen.compileToAssembly()
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import prog8.ast.Node
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.absolute
|
||||
import kotlin.io.path.div
|
||||
|
||||
|
||||
/**************************** AST Data classes ****************************/
|
||||
@ -191,7 +192,10 @@ object ParentSentinel : Node {
|
||||
|
||||
data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
|
||||
override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]"
|
||||
fun toClickableStr(): String = "(${Path("").absolute()}/$file:$line:$startCol)"
|
||||
fun toClickableStr(): String {
|
||||
val path = (Path("") / file).absolute().normalize()
|
||||
return "($path:$line:$startCol)"
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DUMMY = Position("<dummy>", 0, 0, 0)
|
||||
|
@ -4,11 +4,13 @@ TODO
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- programGen: don't generate variables from the VarDecl nodes, use allocator/zeropage tables
|
||||
|
||||
after that is done:
|
||||
|
||||
- (newvaralloc) UnusedCodeRemover after(decl: VarDecl): fix that vars defined in a library can also safely be removed if unused. Currently this breaks programs such as textelite (due to diskio.save().end_address ?)
|
||||
- remove hacks in VariableAllocator
|
||||
- check that retval_interm_* are not in the varallocation if they're not used
|
||||
- make it so that subroutine parameters as variables can again be allocated in ZP, if there's still space
|
||||
- wormfood became a lot larger??? why??? (and chess a little bit larger, but usually program size is down)
|
||||
- check: are prog8_lib.P8ZP_SCRATCH emitted again from prog8_lib.p8 source, or do we only have the correct hardcoded redefines.
|
||||
|
||||
|
||||
Need help with
|
||||
|
@ -18,6 +18,14 @@ main {
|
||||
|
||||
sub start() {
|
||||
prog8_lib.P8ZP_SCRATCH_B1 = 1
|
||||
prog8_lib.P8ZP_SCRATCH_W1 = 1111
|
||||
|
||||
txt.print_uwhex(&prog8_lib.P8ZP_SCRATCH_B1, true)
|
||||
txt.spc()
|
||||
txt.print_uwhex(&prog8_lib.P8ZP_SCRATCH_W1, true)
|
||||
txt.spc()
|
||||
txt.print_uwhex(&prog8_lib.P8ZP_SCRATCH_W2, true)
|
||||
txt.nl()
|
||||
|
||||
txt.print_uw(nullwords[1])
|
||||
txt.nl()
|
||||
|
Loading…
x
Reference in New Issue
Block a user